├── lib └── waveshare_epd │ ├── __init__.py │ ├── epdconfig.py │ ├── epd4in2bc.py │ ├── epd4in2b_V2.py │ ├── epd1in54c.py │ ├── epd2in9bc.py │ ├── epd2in13bc.py │ ├── epd2in13b_V3.py │ ├── epd2in9b_V3.py │ ├── epd7in5_V2.py │ ├── epd5in83_V2.py │ ├── epd5in83b_V2.py │ ├── epd1in54b_V2.py │ ├── epd7in5b_V2.py │ ├── epd2in66b.py │ ├── epd2in7b_V2.py │ ├── epd7in5_HD.py │ ├── epd5in83bc.py │ ├── epd7in5bc.py │ ├── epd5in83.py │ ├── epd7in5b_HD.py │ ├── epd7in5.py │ ├── epd1in54_V2.py │ ├── epd2in9.py │ ├── epd2in66.py │ ├── epd2in13.py │ ├── epd2in9_V2.py │ ├── epd1in54b.py │ └── epd4in01f.py ├── requirements.txt ├── O365CalendarPi.png ├── fonts ├── Ubuntu-B.ttf ├── Ubuntu-M.ttf └── Ubuntu-MI.ttf ├── run.sh ├── init_auth_token.py ├── event.py ├── cal.py ├── cal_fetcher.py ├── main.py ├── .gitignore ├── README.md └── display.py /lib/waveshare_epd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | O365==2.0.13 2 | Pillow==8.0.1 3 | spidev==3.5 4 | RPi.GPIO==0.7.0 -------------------------------------------------------------------------------- /O365CalendarPi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaunhall/O365CalendarPi/HEAD/O365CalendarPi.png -------------------------------------------------------------------------------- /fonts/Ubuntu-B.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaunhall/O365CalendarPi/HEAD/fonts/Ubuntu-B.ttf -------------------------------------------------------------------------------- /fonts/Ubuntu-M.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaunhall/O365CalendarPi/HEAD/fonts/Ubuntu-M.ttf -------------------------------------------------------------------------------- /fonts/Ubuntu-MI.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaunhall/O365CalendarPi/HEAD/fonts/Ubuntu-MI.ttf -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | cd $DIR 6 | PYTHONHASHSEED=0 ./venv/bin/python main.py $1 -------------------------------------------------------------------------------- /init_auth_token.py: -------------------------------------------------------------------------------- 1 | from O365 import Account 2 | # the default protocol will be Microsoft Graph 3 | # the default authentication method will be "on behalf of a user" 4 | from creds import credentials 5 | 6 | account = Account(credentials, tenant_id="233b013b-d83e-4f7a-86ff-f2e4e7e6946b") 7 | if account.authenticate(scopes=['basic', 'calendar']): 8 | print('Authenticated!') -------------------------------------------------------------------------------- /event.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from dataclasses import dataclass 3 | 4 | 5 | @dataclass 6 | class Event: 7 | start: datetime.datetime 8 | end: datetime.datetime 9 | name: str 10 | different_day: bool 11 | 12 | def __hash__(self) -> int: 13 | return sum([hash(a) for i, a in enumerate([str(self.start.time()), str(self.end.time()), self.name, self.different_day])]) 14 | 15 | -------------------------------------------------------------------------------- /cal.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from dataclasses import dataclass 3 | from typing import List 4 | 5 | from event import Event 6 | 7 | 8 | @dataclass 9 | class Calendar: 10 | name: str 11 | last_updated: datetime.datetime 12 | events: List[Event] 13 | 14 | def __hash__(self) -> int: 15 | return hash(str(self.last_updated.day)) + (0 if not self.events else sum(hash(e)**i for i, e in enumerate(self.events))) 16 | 17 | -------------------------------------------------------------------------------- /cal_fetcher.py: -------------------------------------------------------------------------------- 1 | import datetime as dt 2 | 3 | from O365 import Account, FileSystemTokenBackend 4 | 5 | from cal import Calendar 6 | from event import Event 7 | from pytz import timezone 8 | 9 | class CalendarFetcher: 10 | def __init__(self, token_file_name, tenant_id, creds): 11 | token_backend = FileSystemTokenBackend(token_path='.', token_filename=token_file_name) 12 | self.account = Account(creds, token_backend=token_backend, tenant_id=tenant_id) 13 | 14 | def fetch_calendar(self): 15 | self.account.con.refresh_token() 16 | schedule = self.account.schedule() 17 | 18 | calendar = schedule.get_default_calendar() 19 | 20 | now = dt.datetime.now(tz=timezone("Europe/London")) 21 | tomorrow = now + dt.timedelta(days=1) 22 | tomorrow.replace(hour=0, minute=0, second=0) 23 | q = calendar.new_query('start').greater_equal(now) 24 | q.chain('and').on_attribute('end').less_equal(tomorrow) 25 | 26 | events = map(lambda e: Event(e.start, e.end, e.subject, e.start.day != now.day), filter(lambda e: e.end > now, calendar.get_events(query=q, include_recurring=True))) 27 | 28 | sorted_events = sorted(events, key=lambda e: e.start) 29 | return Calendar(self.account.get_current_user().display_name, now, list(sorted_events)) -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | import os 4 | 5 | import display 6 | from cal_fetcher import CalendarFetcher 7 | from creds import credentials 8 | 9 | parser = argparse.ArgumentParser(description='Render your O365 calendar on a pi') 10 | parser.add_argument('--rotate', default=False, 11 | help='rotate the display by 180 degrees') 12 | args = parser.parse_args() 13 | 14 | state_path = "./state_hash.txt" 15 | def is_new_state(state): 16 | if os.path.exists(state_path): 17 | with open(state_path) as f: 18 | return f.readline() != state 19 | else: 20 | return True 21 | 22 | def write_state(state): 23 | with open(state_path, "w") as f: 24 | f.write(state) 25 | 26 | 27 | fetcher = CalendarFetcher("o365_token.txt", "233b013b-d83e-4f7a-86ff-f2e4e7e6946b", credentials) 28 | calendar = fetcher.fetch_calendar() 29 | state = str(hash(calendar)) 30 | if is_new_state(state): 31 | write_state(state) 32 | display.render(calendar, rotate=args.rotate) 33 | else: 34 | logging.info("No change to calendar") 35 | # from event import Event 36 | # 37 | # display.render(Calendar("Shaun Hall", datetime.datetime.now(), 38 | # [Event(datetime.datetime.now(), datetime.datetime.now(), "Event number 1"), 39 | # Event(datetime.datetime.now() + datetime.timedelta(hours=1), 40 | # datetime.datetime.now() + datetime.timedelta(hours=2), "Event number 2"), 41 | # Event(datetime.datetime.now() + datetime.timedelta(hours=2), 42 | # datetime.datetime.now() + datetime.timedelta(hours=5), "Event number 3") 43 | # ])) 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | creds.py 2 | o365_token.txt 3 | state_hash.txt 4 | 5 | #for security 6 | config/credentials.json 7 | config/token.pickle 8 | 9 | # Byte-compiled / optimized / DLL files 10 | __pycache__/ 11 | *.py[cod] 12 | *$py.class 13 | 14 | # C extensions 15 | *.so 16 | 17 | # Distribution / packaging 18 | .Python 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | share/python-wheels/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | MANIFEST 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .nox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *.cover 56 | *.py,cover 57 | .hypothesis/ 58 | .pytest_cache/ 59 | cover/ 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | local_settings.py 68 | db.sqlite3 69 | db.sqlite3-journal 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | .pybuilder/ 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # IPython 89 | profile_default/ 90 | ipython_config.py 91 | 92 | # pyenv 93 | # For a library or package, you might want to ignore these files since the code is 94 | # intended to run in multiple environments; otherwise, check them in: 95 | # .python-version 96 | 97 | # pipenv 98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 101 | # install all needed dependencies. 102 | #Pipfile.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # O365 Calendar on a Raspberry Pi and e-Ink Display 2 | 3 | ![A picture of the setup](O365CalendarPi.png) 4 | 5 | ## Motivation 6 | I found myself frequently checking my calendar throughout the day and sometimes reserving a monitor for it. This low-cost, low-power setup saves me a tab and a couple of clicks per day! 7 | 8 | The small screen (2.13") presents a few challenges in displaying the data. I decided to show the start time of each meeting with the duration indicated by blocks on the right hand side (1 block = 30 mins). A solid line demarcates between today and tomorrow's meetings. 9 | 10 | ## Hardware 11 | 12 | * [Raspberry Pi Zero](https://thepihut.com/products/raspberry-pi-zero-w) 13 | * [Waveshare 2.13" e-ink display](https://thepihut.com/products/three-colour-2-13-eink-display-phat-red-black-white) 14 | * [Case](https://thepihut.com/products/pi-zero-case-for-waveshare-2-13-eink-display) 15 | 16 | Total cost is around £35 17 | 18 | ## O365 Tokens 19 | You need to register a new app against your O365 account with permission to read from your calendar. To do this: 20 | * Go to [App Registrations](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) 21 | * Create a new registration 22 | * The supported account type should be "Accounts in this organizational directory only". No redirect URI is required. 23 | * Open your registration, and under "Client credentials", click "Add a certificate or secret" 24 | * Add a new client secret with an expiry date of your choice 25 | * Make a note of your application id and value of your client secret for the deployment step (the secret ID isn't needed) 26 | 27 | ## Deploying to the pi 28 | * Clone this repo into your desired location (e.g. /home/pi/O365CalendarPi) 29 | * Using your favourite text editor, populate a new file called `creds.py` with `credentials = ('application id', 'client secret value')` from the previous step 30 | * Create a virtual environment in this directory: 31 | ```bash 32 | python3 -m venv venv 33 | ``` 34 | * Activate the virtual environment and install dependencies: 35 | ```bash 36 | source venv/bin/activate && pip install -r requirements.txt 37 | ``` 38 | * Initialise your O365 token by running ```python init_auth_token.py```. You only need to run this once. 39 | * Run this to check it works `/home/pi/O365CalendarPi/run.sh` 40 | * To update every 15 minutes, add the following line to /etc/crontab: 41 | ```bash 42 | */15 * * * * pi /home/pi/O365CalendarPi/run.sh > /home/pi/log.txt 43 | ``` 44 | * Note that it will only redraw on the screen when the data on the screen changes (this increases the lifetime of the screen). 45 | 46 | ## `run.sh` arguments 47 | 48 | The `rotate` flag determines whether to rotate the display by 180 degrees or not (default is not). e.g. 49 | `./run.sh --rotate=True` 50 | 51 | ## Further Work 52 | 53 | I would like to generalise to support other calendars and support different size displays. Contributions are very welcome. 54 | -------------------------------------------------------------------------------- /display.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | import sys 4 | import os 5 | 6 | from cal import Calendar 7 | 8 | fontdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'fonts') 9 | 10 | 11 | import logging 12 | import time 13 | from PIL import Image, ImageDraw, ImageFont 14 | libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib') 15 | if os.path.exists(libdir): 16 | sys.path.append(libdir) 17 | 18 | logging.basicConfig(level=logging.DEBUG) 19 | 20 | 21 | def suffix(day): 22 | if 4 <= day <= 20 or 24 <= day <= 30: 23 | return "th" 24 | else: 25 | return ["st", "nd", "rd"][day % 10 - 1] 26 | 27 | def time_format(event): 28 | return event.strftime("%H:%M") 29 | 30 | def render(calendar: Calendar, debug=False, rotate=False): 31 | if not debug: 32 | from waveshare_epd import epd2in13b_V3 33 | try: 34 | logging.info("epd2in13b_V3 Demo") 35 | day_suffix = suffix(int(calendar.last_updated.strftime("%d"))) 36 | title_part1 = f'{calendar.last_updated.strftime(f"%A %-d")}' 37 | title = f'{title_part1} {calendar.last_updated.strftime("%B")}' 38 | 39 | if not debug: 40 | epd = epd2in13b_V3.EPD() 41 | logging.info("init and Clear") 42 | epd.init() 43 | epd.Clear() 44 | time.sleep(1) 45 | 46 | # Drawing on the image 47 | logging.info("Drawing") 48 | font_main = ImageFont.truetype(os.path.join(fontdir, 'Ubuntu-M.ttf'), 16) 49 | font_small = ImageFont.truetype(os.path.join(fontdir, 'Ubuntu-M.ttf'), 10) 50 | 51 | # Drawing on the Horizontal image 52 | logging.info("1.Drawing on the Horizontal image...") 53 | width = 212 54 | if debug: 55 | HBlackimage = Image.new('1', (width, 104), 255) 56 | HRYimage = Image.new('1', (width, 104), 255) 57 | else: 58 | HBlackimage = Image.new('1', (epd.height, epd.width), 255) 59 | HRYimage = Image.new('1', (epd.height, epd.width), 255) 60 | drawblack = ImageDraw.Draw(HBlackimage) 61 | drawry = ImageDraw.Draw(HRYimage) 62 | w, h = drawblack.textsize(title, font=font_main) 63 | w_p1, h = drawblack.textsize(title_part1, font=font_main) 64 | drawblack.text(((width - w) / 2, 0), title, font=font_main, fill=0) 65 | drawblack.text(((width - w) / 2 + w_p1 + 1, 0), day_suffix, font=font_small, fill=0) 66 | drawblack.line((52, 20, 52, epd.width), fill=0) 67 | y = 20 68 | line_height = 20 69 | different_day = False 70 | for event in calendar.events[:4]: 71 | if event.different_day and not different_day: 72 | different_day = True 73 | drawblack.rectangle((0, y - 3, epd.height, y - 1), outline=0, fill=0) 74 | drawblack.text((5, y), time_format(event.start), font=font_main, fill=0) 75 | for num_chars in range(14, 25): 76 | if drawry.textsize(f"{event.name[:num_chars]}", font=font_main)[0] > 118: 77 | break 78 | drawry.text((59, y), f"{event.name[:num_chars]}", font=font_main, fill=0) 79 | num_blocks = round((event.end - event.start).total_seconds() // (60*30)) 80 | block_width = (line_height // 2 - 1) 81 | for i in range(min(4, num_blocks)): 82 | x_top = 190 + (i // 2) * block_width 83 | y_top = y + (i % 2) * block_width 84 | draw = drawblack if i % 3 else drawry 85 | draw.rectangle((x_top, y_top, x_top + block_width, y_top + block_width), outline=0, fill=0) 86 | y += line_height 87 | if rotate: 88 | HBlackimage = HBlackimage.rotate(180, Image.NEAREST, expand = 1) 89 | HRYimage = HRYimage.rotate(180, Image.NEAREST, expand = 1) 90 | if not debug: 91 | epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRYimage)) 92 | else: 93 | HBlackimage.show() 94 | HRYimage.show() 95 | 96 | if not debug: 97 | epd.sleep() 98 | time.sleep(3) 99 | epd.Dev_exit() 100 | 101 | except IOError as e: 102 | logging.info(e) 103 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epdconfig.py: -------------------------------------------------------------------------------- 1 | # /***************************************************************************** 2 | # * | File : epdconfig.py 3 | # * | Author : Waveshare team 4 | # * | Function : Hardware underlying interface 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2019-06-21 9 | # * | Info : 10 | # ****************************************************************************** 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import os 31 | import logging 32 | import sys 33 | import time 34 | 35 | 36 | class RaspberryPi: 37 | # Pin definition 38 | RST_PIN = 17 39 | DC_PIN = 25 40 | CS_PIN = 8 41 | BUSY_PIN = 24 42 | 43 | def __init__(self): 44 | import spidev 45 | import RPi.GPIO 46 | 47 | self.GPIO = RPi.GPIO 48 | 49 | # SPI device, bus = 0, device = 0 50 | self.SPI = spidev.SpiDev(0, 0) 51 | 52 | def digital_write(self, pin, value): 53 | self.GPIO.output(pin, value) 54 | 55 | def digital_read(self, pin): 56 | return self.GPIO.input(pin) 57 | 58 | def delay_ms(self, delaytime): 59 | time.sleep(delaytime / 1000.0) 60 | 61 | def spi_writebyte(self, data): 62 | self.SPI.writebytes(data) 63 | 64 | def module_init(self): 65 | self.GPIO.setmode(self.GPIO.BCM) 66 | self.GPIO.setwarnings(False) 67 | self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) 68 | self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) 69 | self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) 70 | self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) 71 | self.SPI.max_speed_hz = 4000000 72 | self.SPI.mode = 0b00 73 | return 0 74 | 75 | def module_exit(self): 76 | logging.debug("spi end") 77 | self.SPI.close() 78 | 79 | logging.debug("close 5V, Module enters 0 power consumption ...") 80 | self.GPIO.output(self.RST_PIN, 0) 81 | self.GPIO.output(self.DC_PIN, 0) 82 | 83 | self.GPIO.cleanup() 84 | 85 | 86 | class JetsonNano: 87 | # Pin definition 88 | RST_PIN = 17 89 | DC_PIN = 25 90 | CS_PIN = 8 91 | BUSY_PIN = 24 92 | 93 | def __init__(self): 94 | import ctypes 95 | find_dirs = [ 96 | os.path.dirname(os.path.realpath(__file__)), 97 | '/usr/local/lib', 98 | '/usr/lib', 99 | ] 100 | self.SPI = None 101 | for find_dir in find_dirs: 102 | so_filename = os.path.join(find_dir, 'sysfs_software_spi.so') 103 | if os.path.exists(so_filename): 104 | self.SPI = ctypes.cdll.LoadLibrary(so_filename) 105 | break 106 | if self.SPI is None: 107 | raise RuntimeError('Cannot find sysfs_software_spi.so') 108 | 109 | import Jetson.GPIO 110 | self.GPIO = Jetson.GPIO 111 | 112 | def digital_write(self, pin, value): 113 | self.GPIO.output(pin, value) 114 | 115 | def digital_read(self, pin): 116 | return self.GPIO.input(self.BUSY_PIN) 117 | 118 | def delay_ms(self, delaytime): 119 | time.sleep(delaytime / 1000.0) 120 | 121 | def spi_writebyte(self, data): 122 | self.SPI.SYSFS_software_spi_transfer(data[0]) 123 | 124 | def module_init(self): 125 | self.GPIO.setmode(self.GPIO.BCM) 126 | self.GPIO.setwarnings(False) 127 | self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) 128 | self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) 129 | self.GPIO.setup(self.CS_PIN, self.GPIO.OUT) 130 | self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN) 131 | self.SPI.SYSFS_software_spi_begin() 132 | return 0 133 | 134 | def module_exit(self): 135 | logging.debug("spi end") 136 | self.SPI.SYSFS_software_spi_end() 137 | 138 | logging.debug("close 5V, Module enters 0 power consumption ...") 139 | self.GPIO.output(self.RST_PIN, 0) 140 | self.GPIO.output(self.DC_PIN, 0) 141 | 142 | self.GPIO.cleanup() 143 | 144 | 145 | if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): 146 | implementation = RaspberryPi() 147 | else: 148 | implementation = JetsonNano() 149 | 150 | for func in [x for x in dir(implementation) if not x.startswith('_')]: 151 | setattr(sys.modules[__name__], func, getattr(implementation, func)) 152 | 153 | 154 | ### END OF FILE ### 155 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd4in2bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd4in2bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 400 35 | EPD_HEIGHT = 300 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 70 | epdconfig.delay_ms(100) 71 | logging.debug("e-Paper busy release") 72 | 73 | def init(self): 74 | if (epdconfig.module_init() != 0): 75 | return -1 76 | 77 | self.reset() 78 | 79 | self.send_command(0x06) # BOOSTER_SOFT_START 80 | self.send_data (0x17) 81 | self.send_data (0x17) 82 | self.send_data (0x17) # 07 0f 17 1f 27 2F 37 2f 83 | 84 | self.send_command(0x04) # POWER_ON 85 | self.ReadBusy() 86 | 87 | self.send_command(0x00) # PANEL_SETTING 88 | self.send_data(0x0F) # LUT from OTP 89 | 90 | return 0 91 | 92 | def getbuffer(self, image): 93 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 94 | buf = [0xFF] * (int(self.width/8) * self.height) 95 | image_monocolor = image.convert('1') 96 | imwidth, imheight = image_monocolor.size 97 | pixels = image_monocolor.load() 98 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 99 | if(imwidth == self.width and imheight == self.height): 100 | logging.debug("Horizontal") 101 | for y in range(imheight): 102 | for x in range(imwidth): 103 | # Set the bits for the column of pixels at the current position. 104 | if pixels[x, y] == 0: 105 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 106 | elif(imwidth == self.height and imheight == self.width): 107 | logging.debug("Vertical") 108 | for y in range(imheight): 109 | for x in range(imwidth): 110 | newx = y 111 | newy = self.height - x - 1 112 | if pixels[x, y] == 0: 113 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 114 | return buf 115 | 116 | def display(self, imageblack, imagered): 117 | self.send_command(0x10) 118 | for i in range(0, int(self.width * self.height / 8)): 119 | self.send_data(imageblack[i]) 120 | 121 | self.send_command(0x13) 122 | for i in range(0, int(self.width * self.height / 8)): 123 | self.send_data(imagered[i]) 124 | 125 | self.send_command(0x12) 126 | self.ReadBusy() 127 | 128 | def Clear(self): 129 | self.send_command(0x10) 130 | for i in range(0, int(self.width * self.height / 8)): 131 | self.send_data(0xFF) 132 | 133 | self.send_command(0x13) 134 | for i in range(0, int(self.width * self.height / 8)): 135 | self.send_data(0xFF) 136 | 137 | self.send_command(0x12) 138 | self.ReadBusy() 139 | 140 | def sleep(self): 141 | self.send_command(0x02) # POWER_OFF 142 | self.ReadBusy() 143 | self.send_command(0x07) # DEEP_SLEEP 144 | self.send_data(0xA5) # check code 145 | 146 | def Dev_exit(self): 147 | epdconfig.module_exit() 148 | ### END OF FILE ### 149 | 150 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd4in2b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd4in2bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 400 35 | EPD_HEIGHT = 300 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | self.send_command(0x71); 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | self.send_command(0x71); 72 | epdconfig.delay_ms(20) 73 | logging.debug("e-Paper busy release") 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | 79 | self.reset() 80 | 81 | self.send_command(0x04); 82 | self.ReadBusy(); 83 | 84 | self.send_command(0x00); 85 | self.send_data(0x0f); 86 | 87 | return 0 88 | 89 | def getbuffer(self, image): 90 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 91 | buf = [0xFF] * (int(self.width/8) * self.height) 92 | image_monocolor = image.convert('1') 93 | imwidth, imheight = image_monocolor.size 94 | pixels = image_monocolor.load() 95 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 96 | if(imwidth == self.width and imheight == self.height): 97 | logging.debug("Horizontal") 98 | for y in range(imheight): 99 | for x in range(imwidth): 100 | # Set the bits for the column of pixels at the current position. 101 | if pixels[x, y] == 0: 102 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 103 | elif(imwidth == self.height and imheight == self.width): 104 | logging.debug("Vertical") 105 | for y in range(imheight): 106 | for x in range(imwidth): 107 | newx = y 108 | newy = self.height - x - 1 109 | if pixels[x, y] == 0: 110 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 111 | return buf 112 | 113 | def display(self, imageblack, imagered): 114 | self.send_command(0x10) 115 | for i in range(0, int(self.width * self.height / 8)): 116 | self.send_data(imageblack[i]) 117 | 118 | self.send_command(0x13) 119 | for i in range(0, int(self.width * self.height / 8)): 120 | self.send_data(imagered[i]) 121 | 122 | self.send_command(0x12) 123 | epdconfig.delay_ms(20) 124 | self.ReadBusy() 125 | 126 | def Clear(self): 127 | self.send_command(0x10) 128 | for i in range(0, int(self.width * self.height / 8)): 129 | self.send_data(0xFF) 130 | 131 | self.send_command(0x13) 132 | for i in range(0, int(self.width * self.height / 8)): 133 | self.send_data(0xFF) 134 | 135 | self.send_command(0x12) 136 | epdconfig.delay_ms(20) 137 | self.ReadBusy() 138 | 139 | def sleep(self): 140 | self.send_command(0X50); 141 | self.send_data(0xf7); #border floating 142 | 143 | self.send_command(0X02); #power off 144 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 145 | self.send_command(0X07); #deep sleep 146 | self.send_data(0xA5); 147 | 148 | def Dev_exit(self): 149 | epdconfig.module_exit() 150 | ### END OF FILE ### 151 | 152 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd1in54c.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54c.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | import logging 30 | from . import epdconfig 31 | 32 | # Display resolution 33 | EPD_WIDTH = 152 34 | EPD_HEIGHT = 152 35 | 36 | class EPD: 37 | def __init__(self): 38 | self.reset_pin = epdconfig.RST_PIN 39 | self.dc_pin = epdconfig.DC_PIN 40 | self.busy_pin = epdconfig.BUSY_PIN 41 | self.cs_pin = epdconfig.CS_PIN 42 | self.width = EPD_WIDTH 43 | self.height = EPD_HEIGHT 44 | 45 | # Hardware reset 46 | def reset(self): 47 | epdconfig.digital_write(self.reset_pin, 1) 48 | epdconfig.delay_ms(10) 49 | epdconfig.digital_write(self.reset_pin, 0) 50 | epdconfig.delay_ms(1) 51 | epdconfig.digital_write(self.reset_pin, 1) 52 | epdconfig.delay_ms(10) 53 | 54 | def send_command(self, command): 55 | epdconfig.digital_write(self.dc_pin, 0) 56 | epdconfig.digital_write(self.cs_pin, 0) 57 | epdconfig.spi_writebyte([command]) 58 | epdconfig.digital_write(self.cs_pin, 1) 59 | 60 | def send_data(self, data): 61 | epdconfig.digital_write(self.dc_pin, 1) 62 | epdconfig.digital_write(self.cs_pin, 0) 63 | epdconfig.spi_writebyte([data]) 64 | epdconfig.digital_write(self.cs_pin, 1) 65 | 66 | def ReadBusy(self): 67 | logging.debug("e-Paper busy") 68 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 69 | epdconfig.delay_ms(200) 70 | logging.debug("e-Paper busy release") 71 | 72 | def init(self): 73 | if (epdconfig.module_init() != 0): 74 | return -1 75 | # EPD hardware init start 76 | self.reset() 77 | 78 | self.send_command(0x06) # boost soft start 79 | self.send_data(0x17) 80 | self.send_data(0x17) 81 | self.send_data(0x17) 82 | self.send_command(0x04) # power on 83 | 84 | self.ReadBusy() 85 | 86 | self.send_command(0x00) # panel setting 87 | self.send_data(0x0f) # LUT from OTP,160x296 88 | self.send_data(0x0d) # VCOM to 0V fast 89 | 90 | self.send_command(0x61) # resolution setting 91 | self.send_data(0x98) 92 | self.send_data(0x00) 93 | self.send_data(0x98) 94 | 95 | self.send_command(0x50) 96 | self.send_data(0x77) 97 | 98 | def getbuffer(self, image): 99 | buf = [0xFF] * (int(self.width/8) * self.height) 100 | image_monocolor = image.convert('1') 101 | imwidth, imheight = image_monocolor.size 102 | pixels = image_monocolor.load() 103 | if(imwidth == self.width and imheight == self.height): 104 | logging.debug("Horizontal") 105 | for y in range(imheight): 106 | for x in range(imwidth): 107 | # Set the bits for the column of pixels at the current position. 108 | if pixels[x, y] == 0: 109 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 110 | elif(imwidth == self.height and imheight == self.width): 111 | logging.debug("Vertical") 112 | for y in range(imheight): 113 | for x in range(imwidth): 114 | newx = y 115 | newy = self.height - x - 1 116 | if pixels[x, y] == 0: 117 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 118 | return buf 119 | 120 | def display(self, blackimage, yellowimage): 121 | self.send_command(0x10) 122 | logging.debug("blackimage") 123 | for i in range(0, int(self.width * self.height / 8)): 124 | self.send_data(blackimage[i]) 125 | self.send_command(0x13) 126 | logging.debug("yellowimage") 127 | for i in range(0, int(self.width * self.height / 8)): 128 | self.send_data(yellowimage[i]) 129 | 130 | self.send_command(0x12) 131 | self.ReadBusy() 132 | 133 | def Clear(self): 134 | self.send_command(0x10) 135 | for i in range(0, int(self.width * self.height / 8)): 136 | self.send_data(0xFF) 137 | self.send_command(0x13) 138 | for i in range(0, int(self.width * self.height / 8)): 139 | self.send_data(0xFF) 140 | 141 | self.send_command(0x12) 142 | self.ReadBusy() 143 | 144 | # after this, call epd.init() to awaken the module 145 | def sleep(self): 146 | self.send_command(0X02) # power off 147 | self.ReadBusy() 148 | self.send_command(0X07) # deep sleep 149 | self.send_data(0xA5) 150 | 151 | def Dev_exit(self): 152 | epdconfig.module_exit() 153 | ### END OF FILE ### 154 | 155 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in9bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 128 36 | EPD_HEIGHT = 296 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(200) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | # EPD hardware init start 78 | self.reset() 79 | 80 | self.send_command(0x06) # boost 81 | self.send_data (0x17) 82 | self.send_data (0x17) 83 | self.send_data (0x17) 84 | self.send_command(0x04) # POWER_ON 85 | self.ReadBusy() 86 | self.send_command(0X00) # PANEL_SETTING 87 | self.send_data(0x8F) 88 | self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING 89 | self.send_data(0x77) 90 | self.send_command(0x61) # TCON_RESOLUTION 91 | self.send_data (0x80) 92 | self.send_data (0x01) 93 | self.send_data (0x28) 94 | # self.send_command(VCM_DC_SETTING_REGISTER) 95 | # self.send_data (0x0A) 96 | 97 | return 0 98 | 99 | def getbuffer(self, image): 100 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 101 | buf = [0xFF] * (int(self.width/8) * self.height) 102 | image_monocolor = image.convert('1') 103 | imwidth, imheight = image_monocolor.size 104 | pixels = image_monocolor.load() 105 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 106 | if(imwidth == self.width and imheight == self.height): 107 | logging.debug("Vertical") 108 | for y in range(imheight): 109 | for x in range(imwidth): 110 | # Set the bits for the column of pixels at the current position. 111 | if pixels[x, y] == 0: 112 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 113 | elif(imwidth == self.height and imheight == self.width): 114 | logging.debug("Horizontal") 115 | for y in range(imheight): 116 | for x in range(imwidth): 117 | newx = y 118 | newy = self.height - x - 1 119 | if pixels[x, y] == 0: 120 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 121 | return buf 122 | 123 | def display(self, blackimage, ryimage): # ryimage: red or yellow image 124 | if (blackimage != None): 125 | self.send_command(0X10) 126 | for i in range(0, int(self.width * self.height / 8)): 127 | self.send_data(blackimage[i]) 128 | if (ryimage != None): 129 | self.send_command(0X13) 130 | for i in range(0, int(self.width * self.height / 8)): 131 | self.send_data(ryimage[i]) 132 | 133 | self.send_command(0x12) 134 | self.ReadBusy() 135 | 136 | def Clear(self): 137 | self.send_command(0X10) 138 | for i in range(0, int(self.width * self.height / 8)): 139 | self.send_data(0xff) 140 | self.send_command(0X13) 141 | for i in range(0, int(self.width * self.height / 8)): 142 | self.send_data(0xff) 143 | 144 | self.send_command(0x12) 145 | self.ReadBusy() 146 | 147 | def sleep(self): 148 | self.send_command(0X02) # power off 149 | self.ReadBusy() 150 | self.send_command(0X07) # deep sleep 151 | self.send_data(0xA5) 152 | 153 | def Dev_exit(self): 154 | epdconfig.module_exit() 155 | ### END OF FILE ### 156 | 157 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in13bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 104 35 | EPD_HEIGHT = 212 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 70 | epdconfig.delay_ms(100) 71 | logging.debug("e-Paper busy release") 72 | 73 | def init(self): 74 | if (epdconfig.module_init() != 0): 75 | return -1 76 | 77 | self.reset() 78 | 79 | self.send_command(0x06) # BOOSTER_SOFT_START 80 | self.send_data(0x17) 81 | self.send_data(0x17) 82 | self.send_data(0x17) 83 | 84 | self.send_command(0x04) # POWER_ON 85 | self.ReadBusy() 86 | 87 | self.send_command(0x00) # PANEL_SETTING 88 | self.send_data(0x8F) 89 | 90 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 91 | self.send_data(0xF0) 92 | 93 | self.send_command(0x61) # RESOLUTION_SETTING 94 | self.send_data(self.width & 0xff) 95 | self.send_data(self.height >> 8) 96 | self.send_data(self.height & 0xff) 97 | return 0 98 | 99 | def getbuffer(self, image): 100 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 101 | buf = [0xFF] * (int(self.width/8) * self.height) 102 | image_monocolor = image.convert('1') 103 | imwidth, imheight = image_monocolor.size 104 | pixels = image_monocolor.load() 105 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 106 | if(imwidth == self.width and imheight == self.height): 107 | logging.debug("Vertical") 108 | for y in range(imheight): 109 | for x in range(imwidth): 110 | # Set the bits for the column of pixels at the current position. 111 | if pixels[x, y] == 0: 112 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 113 | elif(imwidth == self.height and imheight == self.width): 114 | logging.debug("Horizontal") 115 | for y in range(imheight): 116 | for x in range(imwidth): 117 | newx = y 118 | newy = self.height - x - 1 119 | if pixels[x, y] == 0: 120 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 121 | return buf 122 | 123 | def display(self, imageblack, imagered): 124 | self.send_command(0x10) 125 | for i in range(0, int(self.width * self.height / 8)): 126 | self.send_data(imageblack[i]) 127 | # self.send_command(0x92) 128 | 129 | self.send_command(0x13) 130 | for i in range(0, int(self.width * self.height / 8)): 131 | self.send_data(imagered[i]) 132 | # self.send_command(0x92) 133 | 134 | self.send_command(0x12) # REFRESH 135 | self.ReadBusy() 136 | 137 | def Clear(self): 138 | self.send_command(0x10) 139 | for i in range(0, int(self.width * self.height / 8)): 140 | self.send_data(0xFF) 141 | self.send_command(0x92) 142 | 143 | self.send_command(0x13) 144 | for i in range(0, int(self.width * self.height / 8)): 145 | self.send_data(0xFF) 146 | self.send_command(0x92) 147 | 148 | self.send_command(0x12) # REFRESH 149 | self.ReadBusy() 150 | 151 | def sleep(self): 152 | self.send_command(0x02) # POWER_OFF 153 | self.ReadBusy() 154 | self.send_command(0x07) # DEEP_SLEEP 155 | self.send_data(0xA5) # check code 156 | 157 | def Dev_exit(self): 158 | epdconfig.module_exit() 159 | ### END OF FILE ### 160 | 161 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in13b_V3.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 104 35 | EPD_HEIGHT = 212 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | self.send_command(0x71); 70 | while(epdconfig.digital_read(self.busy_pin) == 0): 71 | self.send_command(0x71); 72 | epdconfig.delay_ms(100) 73 | logging.debug("e-Paper busy release") 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | 79 | self.reset() 80 | self.send_command(0x04); 81 | self.ReadBusy();#waiting for the electronic paper IC to release the idle signal 82 | 83 | self.send_command(0x00); #panel setting 84 | self.send_data(0x0f); #LUT from OTP,128x296 85 | self.send_data(0x89); #Temperature sensor, boost and other related timing settings 86 | 87 | self.send_command(0x61); #resolution setting 88 | self.send_data (0x68); 89 | self.send_data (0x00); 90 | self.send_data (0xD4); 91 | 92 | self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING 93 | self.send_data(0x77); #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 94 | # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 95 | 96 | return 0 97 | 98 | def getbuffer(self, image): 99 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 100 | buf = [0xFF] * (int(self.width/8) * self.height) 101 | image_monocolor = image.convert('1') 102 | imwidth, imheight = image_monocolor.size 103 | pixels = image_monocolor.load() 104 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 105 | if(imwidth == self.width and imheight == self.height): 106 | logging.debug("Vertical") 107 | for y in range(imheight): 108 | for x in range(imwidth): 109 | # Set the bits for the column of pixels at the current position. 110 | if pixels[x, y] == 0: 111 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 112 | elif(imwidth == self.height and imheight == self.width): 113 | logging.debug("Horizontal") 114 | for y in range(imheight): 115 | for x in range(imwidth): 116 | newx = y 117 | newy = self.height - x - 1 118 | if pixels[x, y] == 0: 119 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 120 | return buf 121 | 122 | def display(self, imageblack, imagered): 123 | self.send_command(0x10) 124 | for i in range(0, int(self.width * self.height / 8)): 125 | self.send_data(imageblack[i]) 126 | 127 | self.send_command(0x13) 128 | for i in range(0, int(self.width * self.height / 8)): 129 | self.send_data(imagered[i]) 130 | 131 | self.send_command(0x12) # REFRESH 132 | epdconfig.delay_ms(100) 133 | self.ReadBusy() 134 | 135 | def Clear(self): 136 | self.send_command(0x10) 137 | for i in range(0, int(self.width * self.height / 8)): 138 | self.send_data(0xFF) 139 | 140 | self.send_command(0x13) 141 | for i in range(0, int(self.width * self.height / 8)): 142 | self.send_data(0xFF) 143 | 144 | self.send_command(0x12) # REFRESH 145 | epdconfig.delay_ms(100) 146 | self.ReadBusy() 147 | 148 | def sleep(self): 149 | self.send_command(0X50) 150 | self.send_data(0xf7) 151 | self.send_command(0X02) 152 | self.ReadBusy() 153 | self.send_command(0x07) # DEEP_SLEEP 154 | self.send_data(0xA5) # check code 155 | 156 | def Dev_exit(self): 157 | epdconfig.module_exit() 158 | ### END OF FILE ### 159 | 160 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in9b_V3.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9b_V3.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.1 8 | # * | Date : 2020-12-03 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 128 36 | EPD_HEIGHT = 296 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(2) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | self.send_command(0X71) 71 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 72 | self.send_command(0X71) 73 | epdconfig.delay_ms(200) 74 | logging.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | # EPD hardware init start 80 | self.reset() 81 | 82 | self.send_command(0x04) 83 | self.ReadBusy()#waiting for the electronic paper IC to release the idle signal 84 | 85 | self.send_command(0x00) #panel setting 86 | self.send_data(0x0f) #LUT from OTP,128x296 87 | self.send_data(0x89) #Temperature sensor, boost and other related timing settings 88 | 89 | self.send_command(0x61) #resolution setting 90 | self.send_data (0x80) 91 | self.send_data (0x01) 92 | self.send_data (0x28) 93 | 94 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 95 | self.send_data(0x77) #WBmode:VBDF 17|D7 VBDW 97 VBDB 57 96 | # WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 97 | 98 | return 0 99 | 100 | def getbuffer(self, image): 101 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 102 | buf = [0xFF] * (int(self.width/8) * self.height) 103 | image_monocolor = image.convert('1') 104 | imwidth, imheight = image_monocolor.size 105 | pixels = image_monocolor.load() 106 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 107 | if(imwidth == self.width and imheight == self.height): 108 | logging.debug("Vertical") 109 | for y in range(imheight): 110 | for x in range(imwidth): 111 | # Set the bits for the column of pixels at the current position. 112 | if pixels[x, y] == 0: 113 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 114 | elif(imwidth == self.height and imheight == self.width): 115 | logging.debug("Horizontal") 116 | for y in range(imheight): 117 | for x in range(imwidth): 118 | newx = y 119 | newy = self.height - x - 1 120 | if pixels[x, y] == 0: 121 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 122 | return buf 123 | 124 | def display(self, blackimage, ryimage): # ryimage: red or yellow image 125 | if (blackimage != None): 126 | self.send_command(0X10) 127 | for i in range(0, int(self.width * self.height / 8)): 128 | self.send_data(blackimage[i]) 129 | if (ryimage != None): 130 | self.send_command(0X13) 131 | for i in range(0, int(self.width * self.height / 8)): 132 | self.send_data(ryimage[i]) 133 | 134 | self.send_command(0x12) 135 | epdconfig.delay_ms(200) 136 | self.ReadBusy() 137 | 138 | def Clear(self): 139 | self.send_command(0X10) 140 | for i in range(0, int(self.width * self.height / 8)): 141 | self.send_data(0xff) 142 | self.send_command(0X13) 143 | for i in range(0, int(self.width * self.height / 8)): 144 | self.send_data(0xff) 145 | 146 | self.send_command(0x12) 147 | epdconfig.delay_ms(200) 148 | self.ReadBusy() 149 | 150 | def sleep(self): 151 | self.send_command(0X02) # power off 152 | self.ReadBusy() 153 | self.send_command(0X07) # deep sleep 154 | self.send_data(0xA5) 155 | 156 | def Dev_exit(self): 157 | epdconfig.module_exit() 158 | ### END OF FILE ### 159 | 160 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 800 36 | EPD_HEIGHT = 480 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(2) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | self.send_command(0x71) 71 | busy = epdconfig.digital_read(self.busy_pin) 72 | while(busy == 0): 73 | self.send_command(0x71) 74 | busy = epdconfig.digital_read(self.busy_pin) 75 | epdconfig.delay_ms(200) 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | # EPD hardware init start 81 | self.reset() 82 | 83 | self.send_command(0x01) #POWER SETTING 84 | self.send_data(0x07) 85 | self.send_data(0x07) #VGH=20V,VGL=-20V 86 | self.send_data(0x3f) #VDH=15V 87 | self.send_data(0x3f) #VDL=-15V 88 | 89 | self.send_command(0x04) #POWER ON 90 | epdconfig.delay_ms(100) 91 | self.ReadBusy() 92 | 93 | self.send_command(0X00) #PANNEL SETTING 94 | self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f 95 | 96 | self.send_command(0x61) #tres 97 | self.send_data(0x03) #source 800 98 | self.send_data(0x20) 99 | self.send_data(0x01) #gate 480 100 | self.send_data(0xE0) 101 | 102 | self.send_command(0X15) 103 | self.send_data(0x00) 104 | 105 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 106 | self.send_data(0x10) 107 | self.send_data(0x07) 108 | 109 | self.send_command(0X60) #TCON SETTING 110 | self.send_data(0x22) 111 | 112 | # EPD hardware init end 113 | return 0 114 | 115 | def getbuffer(self, image): 116 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 117 | buf = [0xFF] * (int(self.width/8) * self.height) 118 | image_monocolor = image.convert('1') 119 | imwidth, imheight = image_monocolor.size 120 | pixels = image_monocolor.load() 121 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 122 | if(imwidth == self.width and imheight == self.height): 123 | logging.debug("Vertical") 124 | for y in range(imheight): 125 | for x in range(imwidth): 126 | # Set the bits for the column of pixels at the current position. 127 | if pixels[x, y] == 0: 128 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 129 | elif(imwidth == self.height and imheight == self.width): 130 | logging.debug("Horizontal") 131 | for y in range(imheight): 132 | for x in range(imwidth): 133 | newx = y 134 | newy = self.height - x - 1 135 | if pixels[x, y] == 0: 136 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 137 | return buf 138 | 139 | def display(self, image): 140 | self.send_command(0x13) 141 | for i in range(0, int(self.width * self.height / 8)): 142 | self.send_data(~image[i]) 143 | 144 | self.send_command(0x12) 145 | epdconfig.delay_ms(100) 146 | self.ReadBusy() 147 | 148 | def Clear(self): 149 | self.send_command(0x10) 150 | for i in range(0, int(self.width * self.height / 8)): 151 | self.send_data(0x00) 152 | 153 | self.send_command(0x13) 154 | for i in range(0, int(self.width * self.height / 8)): 155 | self.send_data(0x00) 156 | 157 | self.send_command(0x12) 158 | epdconfig.delay_ms(100) 159 | self.ReadBusy() 160 | 161 | def sleep(self): 162 | self.send_command(0x02) # POWER_OFF 163 | self.ReadBusy() 164 | 165 | self.send_command(0x07) # DEEP_SLEEP 166 | self.send_data(0XA5) 167 | 168 | def Dev_exit(self): 169 | epdconfig.module_exit() 170 | ### END OF FILE ### 171 | 172 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd5in83_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-12-09 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 648 35 | EPD_HEIGHT = 480 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(2) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | while(epdconfig.digital_read(self.busy_pin) == 0): 70 | epdconfig.delay_ms(20) 71 | logging.debug("e-Paper busy release") 72 | 73 | def TurnOnDisplay(self): 74 | self.send_command(0x12); #POWER ON 75 | epdconfig.delay_ms(100) 76 | self.ReadBusy(); 77 | 78 | def init(self): 79 | if (epdconfig.module_init() != 0): 80 | return -1 81 | # EPD hardware init start 82 | self.reset() 83 | 84 | self.send_command(0x01) #POWER SETTING 85 | self.send_data (0x07) 86 | self.send_data (0x07) #VGH=20V,VGL=-20V 87 | self.send_data (0x3f) #VDH=15V 88 | self.send_data (0x3f) #VDL=-15V 89 | 90 | self.send_command(0x04) #POWER ON 91 | epdconfig.delay_ms(100) 92 | self.ReadBusy() #waiting for the electronic paper IC to release the idle signal 93 | 94 | self.send_command(0X00) #PANNEL SETTING 95 | self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f 96 | 97 | self.send_command(0x61) #tres 98 | self.send_data (0x02) #source 648 99 | self.send_data (0x88) 100 | self.send_data (0x01) #gate 480 101 | self.send_data (0xE0) 102 | 103 | self.send_command(0X15) 104 | self.send_data(0x00) 105 | 106 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 107 | self.send_data(0x10) 108 | self.send_data(0x07) 109 | 110 | self.send_command(0X60) #TCON SETTING 111 | self.send_data(0x22) 112 | 113 | # EPD hardware init end 114 | return 0 115 | 116 | def getbuffer(self, image): 117 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 118 | buf = [0xFF] * (int(self.width/8) * self.height) 119 | image_monocolor = image.convert('1') 120 | imwidth, imheight = image_monocolor.size 121 | pixels = image_monocolor.load() 122 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 123 | if(imwidth == self.width and imheight == self.height): 124 | logging.debug("Vertical") 125 | for y in range(imheight): 126 | for x in range(imwidth): 127 | # Set the bits for the column of pixels at the current position. 128 | if pixels[x, y] == 0: 129 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 130 | elif(imwidth == self.height and imheight == self.width): 131 | logging.debug("Horizontal") 132 | for y in range(imheight): 133 | for x in range(imwidth): 134 | newx = y 135 | newy = self.height - x - 1 136 | if pixels[x, y] == 0: 137 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 138 | return buf 139 | 140 | def display(self, image): 141 | self.send_command(0x10) 142 | for i in range(0, int(self.width * self.height / 8)): 143 | self.send_data(0x00) 144 | self.send_command(0x13) 145 | for i in range(0, int(self.width * self.height / 8)): 146 | self.send_data(~image[i]) 147 | self.TurnOnDisplay() 148 | 149 | def Clear(self): 150 | self.send_command(0x10) 151 | for i in range(0, int(self.width * self.height / 8)): 152 | self.send_data(0x00) 153 | self.send_command(0x13) 154 | for i in range(0, int(self.width * self.height / 8)): 155 | self.send_data(0x00) 156 | self.TurnOnDisplay() 157 | 158 | def sleep(self): 159 | self.send_command(0x02) # POWER_OFF 160 | self.ReadBusy() 161 | self.send_command(0x07) # DEEP_SLEEP 162 | self.send_data(0XA5) 163 | 164 | def Dev_exit(self): 165 | epdconfig.module_exit() 166 | 167 | ### END OF FILE ### 168 | 169 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd5in83b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-07-04 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 648 36 | EPD_HEIGHT = 480 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(1) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | self.send_command(0X71) 71 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 72 | self.send_command(0X71) 73 | epdconfig.delay_ms(200) 74 | logging.debug("e-Paper busy release") 75 | 76 | def init(self): 77 | if (epdconfig.module_init() != 0): 78 | return -1 79 | 80 | self.reset() 81 | 82 | self.send_command(0x01) #POWER SETTING 83 | self.send_data (0x07) 84 | self.send_data (0x07) #VGH=20V,VGL=-20V 85 | self.send_data (0x3f) #VDH=15V 86 | self.send_data (0x3f) #VDL=-15V 87 | 88 | self.send_command(0x04) #POWER ON 89 | epdconfig.delay_ms(100) 90 | self.ReadBusy() #waiting for the electronic paper IC to release the idle signal 91 | 92 | self.send_command(0X00) #PANNEL SETTING 93 | self.send_data(0x0F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f 94 | 95 | self.send_command(0x61) #tres 96 | self.send_data (0x02) #source 648 97 | self.send_data (0x88) 98 | self.send_data (0x01) #gate 480 99 | self.send_data (0xe0) 100 | 101 | self.send_command(0X15) 102 | self.send_data(0x00) 103 | 104 | self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING 105 | self.send_data(0x11) 106 | self.send_data(0x07) 107 | 108 | self.send_command(0X60) #TCON SETTING 109 | self.send_data(0x22) 110 | 111 | return 0 112 | 113 | def getbuffer(self, image): 114 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 115 | buf = [0xFF] * (int(self.width/8) * self.height) 116 | image_monocolor = image.convert('1') 117 | imwidth, imheight = image_monocolor.size 118 | pixels = image_monocolor.load() 119 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 120 | if(imwidth == self.width and imheight == self.height): 121 | logging.debug("Vertical") 122 | for y in range(imheight): 123 | for x in range(imwidth): 124 | # Set the bits for the column of pixels at the current position. 125 | if pixels[x, y] == 0: 126 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 127 | elif(imwidth == self.height and imheight == self.width): 128 | logging.debug("Horizontal") 129 | for y in range(imheight): 130 | for x in range(imwidth): 131 | newx = y 132 | newy = self.height - x - 1 133 | if pixels[x, y] == 0: 134 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 135 | return buf 136 | 137 | def display(self, imageblack, imagered): 138 | if (imageblack != None): 139 | self.send_command(0X10) 140 | for i in range(0, int(self.width * self.height / 8)): 141 | self.send_data(imageblack[i]) 142 | if (imagered != None): 143 | self.send_command(0X13) 144 | for i in range(0, int(self.width * self.height / 8)): 145 | self.send_data(~imagered[i]) 146 | 147 | self.send_command(0x12) 148 | epdconfig.delay_ms(200) 149 | self.ReadBusy() 150 | 151 | def Clear(self): 152 | self.send_command(0X10) 153 | for i in range(0, int(self.width * self.height / 8)): 154 | self.send_data(0xff) 155 | self.send_command(0X13) 156 | for i in range(0, int(self.width * self.height / 8)): 157 | self.send_data(0x00) 158 | 159 | self.send_command(0x12) 160 | epdconfig.delay_ms(200) 161 | self.ReadBusy() 162 | 163 | def sleep(self): 164 | self.send_command(0X02) # power off 165 | self.ReadBusy() 166 | self.send_command(0X07) # deep sleep 167 | self.send_data(0xA5) 168 | 169 | def Dev_exit(self): 170 | epdconfig.module_exit() 171 | ### END OF FILE ### 172 | 173 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd1in54b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 200 35 | EPD_HEIGHT = 200 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) # module reset 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 1): 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | # EPD hardware init start 78 | self.reset() 79 | 80 | self.ReadBusy() 81 | self.send_command(0x12) #SWRESET 82 | self.ReadBusy() 83 | 84 | self.send_command(0x01) #Driver output control 85 | self.send_data(0xC7) 86 | self.send_data(0x00) 87 | self.send_data(0x01) 88 | 89 | self.send_command(0x11) #data entry mode 90 | self.send_data(0x01) 91 | 92 | self.send_command(0x44) #set Ram-X address start/end position 93 | self.send_data(0x00) 94 | self.send_data(0x18) #0x18-->(24+1)*8=200 95 | 96 | self.send_command(0x45) #set Ram-Y address start/end position 97 | self.send_data(0xC7) #0xC7-->(199+1)=200 98 | self.send_data(0x00) 99 | self.send_data(0x00) 100 | self.send_data(0x00) 101 | 102 | self.send_command(0x3C) #BorderWavefrom 103 | self.send_data(0x05) 104 | 105 | self.send_command(0x18) #Read built-in temperature sensor 106 | self.send_data(0x80) 107 | 108 | self.send_command(0x4E) # set RAM x address count to 0 109 | self.send_data(0x00) 110 | self.send_command(0x4F) # set RAM y address count to 0X199 111 | self.send_data(0xC7) 112 | self.send_data(0x00) 113 | self.ReadBusy() 114 | return 0 115 | 116 | def getbuffer(self, image): 117 | buf = [0xFF] * int(self.width * self.height / 8) 118 | # Set buffer to value of Python Imaging Library image. 119 | # Image must be in mode 1. 120 | image_monocolor = image.convert('1') 121 | imwidth, imheight = image_monocolor.size 122 | if imwidth != self.width or imheight != self.height: 123 | raise ValueError('Image must be same dimensions as display \ 124 | ({0}x{1}).' .format(self.width, self.height)) 125 | 126 | pixels = image_monocolor.load() 127 | for y in range(self.height): 128 | for x in range(self.width): 129 | # Set the bits for the column of pixels at the current position. 130 | if pixels[x, y] == 0: 131 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 132 | return buf 133 | 134 | def display(self, blackimage, redimage): 135 | # send black data 136 | if (blackimage != None): 137 | self.send_command(0x24) # DATA_START_TRANSMISSION_1 138 | for i in range(0, int(self.width * self.height / 8)): 139 | self.send_data(blackimage[i]) 140 | 141 | # send red data 142 | if (redimage != None): 143 | self.send_command(0x26) # DATA_START_TRANSMISSION_2 144 | for i in range(0, int(self.width * self.height / 8)): 145 | self.send_data(~redimage[i]) 146 | 147 | self.send_command(0x22) # DISPLAY_REFRESH 148 | self.send_data(0xF7) 149 | self.send_command(0x20) # DISPLAY_REFRESH 150 | self.ReadBusy() 151 | 152 | def Clear(self): 153 | self.send_command(0x24) # DATA_START_TRANSMISSION_1 154 | for i in range(0, int(self.width * self.height / 8)): 155 | self.send_data(0xFF) 156 | 157 | self.send_command(0x26) # DATA_START_TRANSMISSION_2 158 | for i in range(0, int(self.width * self.height / 8)): 159 | self.send_data(0x00) 160 | 161 | self.send_command(0x22) # DISPLAY_REFRESH 162 | self.send_data(0xF7) 163 | self.send_command(0x20) # DISPLAY_REFRESH 164 | self.ReadBusy() 165 | 166 | 167 | def sleep(self): 168 | self.send_command(0x10) #enter deep sleep 169 | self.send_data(0x01) 170 | 171 | def Dev_exit(self): 172 | epdconfig.module_exit() 173 | 174 | ### END OF FILE ### 175 | 176 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.1 8 | # * | Date : 2020-11-30 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 800 36 | EPD_HEIGHT = 480 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(4) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | self.send_command(0x71) 71 | busy = epdconfig.digital_read(self.busy_pin) 72 | while(busy == 0): 73 | self.send_command(0x71) 74 | busy = epdconfig.digital_read(self.busy_pin) 75 | epdconfig.delay_ms(200) 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | 81 | self.reset() 82 | 83 | self.send_command(0x01); #POWER SETTING 84 | self.send_data(0x07); 85 | self.send_data(0x07); #VGH=20V,VGL=-20V 86 | self.send_data(0x3f); #VDH=15V 87 | self.send_data(0x3f); #VDL=-15V 88 | 89 | self.send_command(0x04); #POWER ON 90 | epdconfig.delay_ms(100); 91 | self.ReadBusy(); 92 | 93 | self.send_command(0X00); #PANNEL SETTING 94 | self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f 95 | 96 | self.send_command(0x61); #tres 97 | self.send_data(0x03); #source 800 98 | self.send_data(0x20); 99 | self.send_data(0x01); #gate 480 100 | self.send_data(0xE0); 101 | 102 | self.send_command(0X15); 103 | self.send_data(0x00); 104 | 105 | self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING 106 | self.send_data(0x11); 107 | self.send_data(0x07); 108 | 109 | self.send_command(0X60); #TCON SETTING 110 | self.send_data(0x22); 111 | 112 | self.send_command(0x65); 113 | self.send_data(0x00); 114 | self.send_data(0x00); 115 | self.send_data(0x00); 116 | self.send_data(0x00); 117 | 118 | return 0 119 | 120 | def getbuffer(self, image): 121 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 122 | buf = [0xFF] * (int(self.width/8) * self.height) 123 | image_monocolor = image.convert('1') 124 | imwidth, imheight = image_monocolor.size 125 | pixels = image_monocolor.load() 126 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 127 | if(imwidth == self.width and imheight == self.height): 128 | logging.debug("Horizontal") 129 | for y in range(imheight): 130 | for x in range(imwidth): 131 | # Set the bits for the column of pixels at the current position. 132 | if pixels[x, y] == 0: 133 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 134 | elif(imwidth == self.height and imheight == self.width): 135 | logging.debug("Vertical") 136 | for y in range(imheight): 137 | for x in range(imwidth): 138 | newx = y 139 | newy = self.height - x - 1 140 | if pixels[x, y] == 0: 141 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 142 | return buf 143 | 144 | def display(self, imageblack, imagered): 145 | self.send_command(0x10) 146 | for i in range(0, int(self.width * self.height / 8)): 147 | self.send_data(imageblack[i]); 148 | 149 | self.send_command(0x13) 150 | for i in range(0, int(self.width * self.height / 8)): 151 | self.send_data(~imagered[i]); 152 | 153 | self.send_command(0x12) 154 | epdconfig.delay_ms(100) 155 | self.ReadBusy() 156 | 157 | def Clear(self): 158 | self.send_command(0x10) 159 | for i in range(0, int(self.width * self.height / 8)): 160 | self.send_data(0xff) 161 | 162 | self.send_command(0x13) 163 | for i in range(0, int(self.width * self.height / 8)): 164 | self.send_data(0x00) 165 | 166 | self.send_command(0x12) 167 | epdconfig.delay_ms(100) 168 | self.ReadBusy() 169 | 170 | def sleep(self): 171 | self.send_command(0x02) # POWER_OFF 172 | self.ReadBusy() 173 | 174 | self.send_command(0x07) # DEEP_SLEEP 175 | self.send_data(0XA5) 176 | 177 | def Dev_exit(self): 178 | epdconfig.module_exit() 179 | ### END OF FILE ### 180 | 181 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in66b.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in66b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-12-01 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 152 35 | EPD_HEIGHT = 296 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | 63 | def send_data(self, data): 64 | epdconfig.digital_write(self.dc_pin, 1) 65 | epdconfig.digital_write(self.cs_pin, 0) 66 | epdconfig.spi_writebyte([data]) 67 | epdconfig.digital_write(self.cs_pin, 1) 68 | 69 | 70 | def ReadBusy(self): 71 | logging.debug("e-Paper busy") 72 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 73 | epdconfig.delay_ms(20) 74 | logging.debug("e-Paper busy release") 75 | 76 | 77 | def init(self): 78 | if (epdconfig.module_init() != 0): 79 | return -1 80 | # EPD hardware init start 81 | self.reset() 82 | 83 | self.send_command(0x12) 84 | epdconfig.delay_ms(30) 85 | self.ReadBusy() 86 | 87 | self.send_command(0x11) # setting gaet number 88 | self.send_data(0x03) 89 | 90 | self.setWindows(0, 0, self.width-1, self.height-1) 91 | 92 | self.send_command(0x21) 93 | self.send_data(0x00) 94 | self.send_data(0x80) 95 | 96 | self.setCursor(0, 0) 97 | self.ReadBusy() 98 | 99 | return 0 100 | 101 | def setWindows(self, Xstart, Ystart, Xend, Yend): 102 | self.send_command(0x44); # SET_RAM_X_ADDRESS_START_END_POSITION 103 | self.send_data((Xstart>>3) & 0x1F); 104 | self.send_data((Xend>>3) & 0x1F); 105 | 106 | self.send_command(0x45); # SET_RAM_Y_ADDRESS_START_END_POSITION 107 | self.send_data(Ystart & 0xFF); 108 | self.send_data((Ystart >> 8) & 0x01); 109 | self.send_data(Yend & 0xFF); 110 | self.send_data((Yend >> 8) & 0x01); 111 | 112 | def setCursor(self, Xstart, Ystart): 113 | self.send_command(0x4E); # SET_RAM_X_ADDRESS_COUNTER 114 | self.send_data(Xstart & 0x1F); 115 | 116 | self.send_command(0x4F); # SET_RAM_Y_ADDRESS_COUNTER 117 | self.send_data(Ystart & 0xFF); 118 | self.send_data((Ystart >> 8) & 0x01); 119 | 120 | def turnon_display(self): 121 | self.send_command(0x20) 122 | self.ReadBusy() 123 | 124 | def getbuffer(self, image): 125 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 126 | buf = [0xFF] * (int(self.width/8) * self.height) 127 | image_monocolor = image.convert('1') 128 | imwidth, imheight = image_monocolor.size 129 | pixels = image_monocolor.load() 130 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 131 | if(imwidth == self.width and imheight == self.height): 132 | logging.debug("Vertical") 133 | for y in range(imheight): 134 | for x in range(imwidth): 135 | # Set the bits for the column of pixels at the current position. 136 | if pixels[x, y] == 0: 137 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 138 | elif(imwidth == self.height and imheight == self.width): 139 | logging.debug("Horizontal") 140 | for y in range(imheight): 141 | for x in range(imwidth): 142 | newx = y 143 | newy = self.height - x - 1 144 | if pixels[x, y] == 0: 145 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 146 | return buf 147 | 148 | def display(self, Blackimage, Redimage): 149 | if (Blackimage == None or Redimage == None): 150 | return 151 | 152 | self.send_command(0x4E) 153 | self.send_data(0x01) 154 | self.send_command(0x4F) 155 | self.send_data(0x27) 156 | self.send_data(0x01) 157 | 158 | self.send_command(0x24) 159 | for j in range(0, self.height): 160 | for i in range(0, int(self.width / 8)): 161 | self.send_data(Blackimage[i + j * int(self.width / 8)]) 162 | 163 | self.send_command(0x26) 164 | for j in range(0, self.height): 165 | for i in range(0, int(self.width / 8)): 166 | self.send_data(~Redimage[i + j * int(self.width / 8)]) 167 | 168 | self.turnon_display() 169 | 170 | 171 | def Clear(self): 172 | 173 | self.send_command(0x24) 174 | for j in range(0, self.height): 175 | for i in range(0, int(self.width / 8)): 176 | self.send_data(0xff) 177 | 178 | self.send_command(0x26) 179 | for j in range(0, self.height): 180 | for i in range(0, int(self.width / 8)): 181 | self.send_data(0x00) 182 | 183 | self.turnon_display() 184 | 185 | 186 | def sleep(self): 187 | self.send_command(0X10) # DEEP_SLEEP_MODE 188 | self.send_data(0x01) 189 | 190 | def Dev_exit(self): 191 | epdconfig.module_exit() 192 | 193 | ### END OF FILE ### 194 | 195 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in7b_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in7b_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-10-22 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 176 36 | EPD_HEIGHT = 264 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | 78 | self.reset() 79 | 80 | self.ReadBusy() 81 | 82 | self.send_command(0x4D) 83 | self.send_data(0xAA) 84 | 85 | self.send_command(0x87) 86 | self.send_data(0x28) 87 | 88 | self.send_command(0x84) 89 | self.send_data(0x00) 90 | 91 | self.send_command(0x83) 92 | self.send_data(0x05) 93 | 94 | self.send_command(0xA8) 95 | self.send_data(0xDF) 96 | 97 | self.send_command(0xA9) 98 | self.send_data(0x05) 99 | 100 | self.send_command(0xB1) 101 | self.send_data(0xE8) 102 | 103 | self.send_command(0xAB) 104 | self.send_data(0xA1) 105 | 106 | self.send_command(0xB9) 107 | self.send_data(0x10) 108 | 109 | self.send_command(0x88) 110 | self.send_data(0x80) 111 | 112 | self.send_command(0x90) 113 | self.send_data(0x02) 114 | 115 | self.send_command(0x86) 116 | self.send_data(0x15) 117 | 118 | self.send_command(0x91) 119 | self.send_data(0x8D) 120 | 121 | self.send_command(0x50) 122 | self.send_data(0x57) 123 | 124 | self.send_command(0xAA) 125 | self.send_data(0x0F) 126 | 127 | self.send_command(0x00) 128 | self.send_data(0x8F) 129 | return 0 130 | 131 | def getbuffer(self, image): 132 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 133 | buf = [0xFF] * (int(self.width/8) * self.height) 134 | image_monocolor = image.convert('1') 135 | imwidth, imheight = image_monocolor.size 136 | pixels = image_monocolor.load() 137 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 138 | if(imwidth == self.width and imheight == self.height): 139 | logging.debug("Vertical") 140 | for y in range(imheight): 141 | for x in range(imwidth): 142 | # Set the bits for the column of pixels at the current position. 143 | if pixels[x, y] == 0: 144 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 145 | elif(imwidth == self.height and imheight == self.width): 146 | logging.debug("Horizontal") 147 | for y in range(imheight): 148 | for x in range(imwidth): 149 | newx = y 150 | newy = self.height - x - 1 151 | if pixels[x, y] == 0: 152 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 153 | return buf 154 | 155 | def display(self, imageblack, imagered): 156 | Width = self.width / 8 157 | Height = self.height 158 | 159 | self.send_command(0x10) 160 | for i in range(0, int(Width * Height)): 161 | self.send_data(imageblack[i]) 162 | 163 | self.send_command(0x13) 164 | for i in range(0, int(Width * Height)): 165 | self.send_data(~imagered[i]) 166 | 167 | self.send_command(0x04) # Power ON 168 | self.ReadBusy() 169 | epdconfig.delay_ms(10) 170 | self.send_command(0x12) # Display Refresh 171 | self.ReadBusy() 172 | epdconfig.delay_ms(10) 173 | self.send_command(0x02) # Power OFF 174 | self.ReadBusy() 175 | epdconfig.delay_ms(20) 176 | 177 | def Clear(self): 178 | self.send_command(0x10) 179 | for i in range(0, int(self.width * self.height / 8)): 180 | self.send_data(0xff) 181 | 182 | self.send_command(0x13) 183 | for i in range(0, int(self.width * self.height / 8)): 184 | self.send_data(0x00) 185 | 186 | self.send_command(0x04) # Power ON 187 | self.ReadBusy() 188 | epdconfig.delay_ms(10) 189 | self.send_command(0x12) # Display Refresh 190 | self.ReadBusy() 191 | epdconfig.delay_ms(10) 192 | self.send_command(0x02) # Power OFF 193 | self.ReadBusy() 194 | epdconfig.delay_ms(20) 195 | 196 | def sleep(self): 197 | self.send_command(0X07) 198 | self.send_data(0xA5) 199 | 200 | def Dev_exit(self): 201 | epdconfig.module_exit() 202 | ### END OF FILE ### 203 | 204 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5_HD.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 880 36 | EPD_HEIGHT = 528 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(2) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | busy = epdconfig.digital_read(self.busy_pin) 71 | while(busy == 1): 72 | busy = epdconfig.digital_read(self.busy_pin) 73 | epdconfig.delay_ms(200) 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | # EPD hardware init start 79 | self.reset() 80 | 81 | self.ReadBusy(); 82 | self.send_command(0x12); #SWRESET 83 | self.ReadBusy(); 84 | 85 | self.send_command(0x46); # Auto Write Red RAM 86 | self.send_data(0xf7); 87 | self.ReadBusy(); 88 | self.send_command(0x47); # Auto Write B/W RAM 89 | self.send_data(0xf7); 90 | self.ReadBusy(); 91 | 92 | self.send_command(0x0C); # Soft start setting 93 | self.send_data(0xAE); 94 | self.send_data(0xC7); 95 | self.send_data(0xC3); 96 | self.send_data(0xC0); 97 | self.send_data(0x40); 98 | 99 | 100 | self.send_command(0x01); # Set MUX as 527 101 | self.send_data(0xAF); 102 | self.send_data(0x02); 103 | self.send_data(0x01);#0x01 104 | 105 | self.send_command(0x11); # Data entry mode 106 | self.send_data(0x01); 107 | 108 | self.send_command(0x44); 109 | self.send_data(0x00); # RAM x address start at 0 110 | self.send_data(0x00); 111 | self.send_data(0x6F); 112 | self.send_data(0x03); 113 | self.send_command(0x45); 114 | self.send_data(0xAF); 115 | self.send_data(0x02); 116 | self.send_data(0x00); 117 | self.send_data(0x00); 118 | 119 | self.send_command(0x3C); # VBD 120 | self.send_data(0x05); # LUT1, for white 121 | 122 | self.send_command(0x18); 123 | self.send_data(0X80); 124 | 125 | 126 | self.send_command(0x22); 127 | self.send_data(0XB1); #Load Temperature and waveform setting. 128 | self.send_command(0x20); 129 | self.ReadBusy(); 130 | 131 | self.send_command(0x4E); # set RAM x address count to 0; 132 | self.send_data(0x00); 133 | self.send_data(0x00); 134 | self.send_command(0x4F); 135 | self.send_data(0x00); 136 | self.send_data(0x00); 137 | # EPD hardware init end 138 | return 0 139 | 140 | def getbuffer(self, image): 141 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 142 | buf = [0xFF] * (int(self.width/8) * self.height) 143 | image_monocolor = image.convert('1') 144 | imwidth, imheight = image_monocolor.size 145 | pixels = image_monocolor.load() 146 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 147 | if(imwidth == self.width and imheight == self.height): 148 | logging.debug("Vertical") 149 | for y in range(imheight): 150 | for x in range(imwidth): 151 | # Set the bits for the column of pixels at the current position. 152 | if pixels[x, y] == 0: 153 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 154 | elif(imwidth == self.height and imheight == self.width): 155 | logging.debug("Horizontal") 156 | for y in range(imheight): 157 | for x in range(imwidth): 158 | newx = y 159 | newy = self.height - x - 1 160 | if pixels[x, y] == 0: 161 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 162 | return buf 163 | 164 | def display(self, image): 165 | self.send_command(0x4F); 166 | self.send_data(0x00); 167 | self.send_data(0x00); 168 | self.send_command(0x24); 169 | for i in range(0, int(self.width * self.height / 8)): 170 | self.send_data(image[i]); 171 | 172 | self.send_command(0x22); 173 | self.send_data(0xF7);#Load LUT from MCU(0x32) 174 | self.send_command(0x20); 175 | epdconfig.delay_ms(10); 176 | self.ReadBusy(); 177 | 178 | def Clear(self): 179 | self.send_command(0x4F); 180 | self.send_data(0x00); 181 | self.send_data(0x00); 182 | self.send_command(0x24) 183 | for i in range(0, int(self.width * self.height / 8)): 184 | self.send_data(0xff) 185 | 186 | self.send_command(0x26) 187 | for i in range(0, int(self.width * self.height / 8)): 188 | self.send_data(0xff) 189 | 190 | self.send_command(0x22); 191 | self.send_data(0xF7);#Load LUT from MCU(0x32) 192 | self.send_command(0x20); 193 | epdconfig.delay_ms(10); 194 | self.ReadBusy(); 195 | 196 | def sleep(self): 197 | self.send_command(0x10); 198 | self.send_data(0x01); 199 | 200 | def Dev_exit(self): 201 | epdconfig.module_exit() 202 | ### END OF FILE ### 203 | 204 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd5in83bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 600 36 | EPD_HEIGHT = 448 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | 78 | self.reset() 79 | 80 | self.send_command(0x01) # POWER_SETTING 81 | self.send_data(0x37) 82 | self.send_data(0x00) 83 | 84 | self.send_command(0x00) # PANEL_SETTING 85 | self.send_data(0xCF) 86 | self.send_data(0x08) 87 | 88 | self.send_command(0x30) # PLL_CONTROL 89 | self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A 90 | self.send_command(0X82) # VCOM VOLTAGE SETTING 91 | self.send_data(0x28) # all temperature range 92 | 93 | self.send_command(0x06) # boost 94 | self.send_data(0xc7) 95 | self.send_data(0xcc) 96 | self.send_data(0x15) 97 | 98 | self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING 99 | self.send_data(0x77) 100 | 101 | self.send_command(0X60) # TCON SETTING 102 | self.send_data(0x22) 103 | 104 | self.send_command(0X65) # FLASH CONTROL 105 | self.send_data(0x00) 106 | 107 | self.send_command(0x61) # tres 108 | self.send_data(0x02) # source 600 109 | self.send_data(0x58) 110 | self.send_data(0x01) # gate 448 111 | self.send_data(0xc0) 112 | 113 | self.send_command(0xe5) # FLASH MODE 114 | self.send_data(0x03) 115 | self.send_data(0x03) 116 | 117 | return 0 118 | 119 | def getbuffer(self, image): 120 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 121 | buf = [0xFF] * (int(self.width/8) * self.height) 122 | image_monocolor = image.convert('1') 123 | imwidth, imheight = image_monocolor.size 124 | pixels = image_monocolor.load() 125 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 126 | if(imwidth == self.width and imheight == self.height): 127 | logging.debug("Horizontal") 128 | for y in range(imheight): 129 | for x in range(imwidth): 130 | # Set the bits for the column of pixels at the current position. 131 | if pixels[x, y] == 0: 132 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 133 | elif(imwidth == self.height and imheight == self.width): 134 | logging.debug("Vertical") 135 | for y in range(imheight): 136 | for x in range(imwidth): 137 | newx = y 138 | newy = self.height - x - 1 139 | if pixels[x, y] == 0: 140 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 141 | return buf 142 | 143 | def display(self, imageblack, imagered): 144 | self.send_command(0x10) 145 | for i in range(0, int(self.width / 8 * self.height)): 146 | temp1 = imageblack[i] 147 | temp2 = imagered[i] 148 | j = 0 149 | while (j < 8): 150 | if ((temp2 & 0x80) == 0x00): 151 | temp3 = 0x04 #red 152 | elif ((temp1 & 0x80) == 0x00): 153 | temp3 = 0x00 #black 154 | else: 155 | temp3 = 0x03 #white 156 | 157 | temp3 = (temp3 << 4) & 0xFF 158 | temp1 = (temp1 << 1) & 0xFF 159 | temp2 = (temp2 << 1) & 0xFF 160 | j += 1 161 | if((temp2 & 0x80) == 0x00): 162 | temp3 |= 0x04 #red 163 | elif ((temp1 & 0x80) == 0x00): 164 | temp3 |= 0x00 #black 165 | else: 166 | temp3 |= 0x03 #white 167 | temp1 = (temp1 << 1) & 0xFF 168 | temp2 = (temp2 << 1) & 0xFF 169 | self.send_data(temp3) 170 | j += 1 171 | 172 | self.send_command(0x04) # POWER ON 173 | self.ReadBusy() 174 | self.send_command(0x12) # display refresh 175 | epdconfig.delay_ms(100) 176 | self.ReadBusy() 177 | 178 | def Clear(self): 179 | self.send_command(0x10) 180 | for i in range(0, int(self.width / 8 * self.height)): 181 | self.send_data(0x33) 182 | self.send_data(0x33) 183 | self.send_data(0x33) 184 | self.send_data(0x33) 185 | 186 | self.send_command(0x04) # POWER ON 187 | self.ReadBusy() 188 | self.send_command(0x12) # display refresh 189 | epdconfig.delay_ms(100) 190 | self.ReadBusy() 191 | 192 | def sleep(self): 193 | self.send_command(0x02) # POWER_OFF 194 | self.ReadBusy() 195 | self.send_command(0x07) # DEEP_SLEEP 196 | self.send_data(0xA5) # check code 197 | 198 | def Dev_exit(self): 199 | epdconfig.module_exit() 200 | ### END OF FILE ### 201 | 202 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5bc.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5bc.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 640 36 | EPD_HEIGHT = 384 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | 78 | self.reset() 79 | 80 | self.send_command(0x01) # POWER_SETTING 81 | self.send_data(0x37) 82 | self.send_data(0x00) 83 | 84 | self.send_command(0x00) # PANEL_SETTING 85 | self.send_data(0xCF) 86 | self.send_data(0x08) 87 | 88 | self.send_command(0x30) # PLL_CONTROL 89 | self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A 90 | 91 | self.send_command(0x82) # VCM_DC_SETTING 92 | self.send_data(0x28) #all temperature range 93 | 94 | self.send_command(0x06) # BOOSTER_SOFT_START 95 | self.send_data(0xc7) 96 | self.send_data(0xcc) 97 | self.send_data(0x15) 98 | 99 | self.send_command(0x50) # VCOM AND DATA INTERVAL SETTING 100 | self.send_data(0x77) 101 | 102 | self.send_command(0x60) # TCON_SETTING 103 | self.send_data(0x22) 104 | 105 | self.send_command(0x65) # FLASH CONTROL 106 | self.send_data(0x00) 107 | 108 | self.send_command(0x61) # TCON_RESOLUTION 109 | self.send_data(self.width >> 8) # source 640 110 | self.send_data(self.width & 0xff) 111 | self.send_data(self.height >> 8) # gate 384 112 | self.send_data(self.height & 0xff) 113 | 114 | self.send_command(0xe5) # FLASH MODE 115 | self.send_data(0x03) 116 | 117 | return 0 118 | 119 | def getbuffer(self, image): 120 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 121 | buf = [0xFF] * (int(self.width/8) * self.height) 122 | image_monocolor = image.convert('1') 123 | imwidth, imheight = image_monocolor.size 124 | pixels = image_monocolor.load() 125 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 126 | if(imwidth == self.width and imheight == self.height): 127 | logging.debug("Horizontal") 128 | for y in range(imheight): 129 | for x in range(imwidth): 130 | # Set the bits for the column of pixels at the current position. 131 | if pixels[x, y] == 0: 132 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 133 | elif(imwidth == self.height and imheight == self.width): 134 | logging.debug("Vertical") 135 | for y in range(imheight): 136 | for x in range(imwidth): 137 | newx = y 138 | newy = self.height - x - 1 139 | if pixels[x, y] == 0: 140 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 141 | return buf 142 | 143 | def display(self, imageblack, imagered): 144 | self.send_command(0x10) 145 | for i in range(0, int(self.width / 8 * self.height)): 146 | temp1 = imageblack[i] 147 | temp2 = imagered[i] 148 | j = 0 149 | while (j < 8): 150 | if ((temp2 & 0x80) == 0x00): 151 | temp3 = 0x04 #red 152 | elif ((temp1 & 0x80) == 0x00): 153 | temp3 = 0x00 #black 154 | else: 155 | temp3 = 0x03 #white 156 | 157 | temp3 = (temp3 << 4) & 0xFF 158 | temp1 = (temp1 << 1) & 0xFF 159 | temp2 = (temp2 << 1) & 0xFF 160 | j += 1 161 | if((temp2 & 0x80) == 0x00): 162 | temp3 |= 0x04 #red 163 | elif ((temp1 & 0x80) == 0x00): 164 | temp3 |= 0x00 #black 165 | else: 166 | temp3 |= 0x03 #white 167 | temp1 = (temp1 << 1) & 0xFF 168 | temp2 = (temp2 << 1) & 0xFF 169 | self.send_data(temp3) 170 | j += 1 171 | 172 | self.send_command(0x04) # POWER ON 173 | self.ReadBusy() 174 | self.send_command(0x12) # display refresh 175 | epdconfig.delay_ms(100) 176 | self.ReadBusy() 177 | 178 | def Clear(self): 179 | self.send_command(0x10) 180 | for i in range(0, int(self.width / 8 * self.height)): 181 | self.send_data(0x33) 182 | self.send_data(0x33) 183 | self.send_data(0x33) 184 | self.send_data(0x33) 185 | 186 | self.send_command(0x04) # POWER ON 187 | self.ReadBusy() 188 | self.send_command(0x12) # display refresh 189 | epdconfig.delay_ms(100) 190 | self.ReadBusy() 191 | 192 | def sleep(self): 193 | self.send_command(0x02) # POWER_OFF 194 | self.ReadBusy() 195 | 196 | self.send_command(0x07) # DEEP_SLEEP 197 | self.send_data(0XA5) 198 | 199 | def Dev_exit(self): 200 | epdconfig.module_exit() 201 | ### END OF FILE ### 202 | 203 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd5in83.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd5in83.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 600 36 | EPD_HEIGHT = 448 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(2) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | # EPD hardware init start 78 | self.reset() 79 | 80 | self.send_command(0x01) # POWER_SETTING 81 | self.send_data(0x37) 82 | self.send_data(0x00) 83 | 84 | self.send_command(0x00) # PANEL_SETTING 85 | self.send_data(0xCF) 86 | self.send_data(0x08) 87 | 88 | self.send_command(0x06) # BOOSTER_SOFT_START 89 | self.send_data(0xc7) 90 | self.send_data(0xcc) 91 | self.send_data(0x28) 92 | 93 | self.send_command(0x04) # POWER_ON 94 | self.ReadBusy() 95 | 96 | self.send_command(0x30) # PLL_CONTROL 97 | self.send_data(0x3c) 98 | 99 | self.send_command(0x41) # TEMPERATURE_CALIBRATION 100 | self.send_data(0x00) 101 | 102 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 103 | self.send_data(0x77) 104 | 105 | self.send_command(0x60) # TCON_SETTING 106 | self.send_data(0x22) 107 | 108 | self.send_command(0x61) # TCON_RESOLUTION 109 | self.send_data(0x02) # source 600 110 | self.send_data(0x58) 111 | self.send_data(0x01) # gate 448 112 | self.send_data(0xC0) 113 | 114 | self.send_command(0x82) # VCM_DC_SETTING 115 | self.send_data(0x1E) # decide by LUT file 116 | 117 | self.send_command(0xe5) # FLASH MODE 118 | self.send_data(0x03) 119 | 120 | # EPD hardware init end 121 | return 0 122 | 123 | def getbuffer(self, image): 124 | buf = [0x00] * int(self.width * self.height / 4) 125 | image_monocolor = image.convert('1') 126 | imwidth, imheight = image_monocolor.size 127 | pixels = image_monocolor.load() 128 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 129 | if(imwidth == self.width and imheight == self.height): 130 | for y in range(imheight): 131 | for x in range(imwidth): 132 | # Set the bits for the column of pixels at the current position. 133 | if pixels[x, y] < 64: # black 134 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 135 | elif pixels[x, y] < 192: # convert gray to red 136 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 137 | buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) 138 | else: # white 139 | buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) 140 | elif(imwidth == self.height and imheight == self.width): 141 | for y in range(imheight): 142 | for x in range(imwidth): 143 | newx = y 144 | newy = self.height - x - 1 145 | if pixels[x, y] < 64: # black 146 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 147 | elif pixels[x, y] < 192: # convert gray to red 148 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 149 | buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) 150 | else: # white 151 | buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) 152 | return buf 153 | 154 | def display(self, image): 155 | self.send_command(0x10) 156 | for i in range(0, int(self.width / 4 * self.height)): 157 | temp1 = image[i] 158 | j = 0 159 | while (j < 4): 160 | if ((temp1 & 0xC0) == 0xC0): 161 | temp2 = 0x03 162 | elif ((temp1 & 0xC0) == 0x00): 163 | temp2 = 0x00 164 | else: 165 | temp2 = 0x04 166 | temp2 = (temp2 << 4) & 0xFF 167 | temp1 = (temp1 << 2) & 0xFF 168 | j += 1 169 | if((temp1 & 0xC0) == 0xC0): 170 | temp2 |= 0x03 171 | elif ((temp1 & 0xC0) == 0x00): 172 | temp2 |= 0x00 173 | else: 174 | temp2 |= 0x04 175 | temp1 = (temp1 << 2) & 0xFF 176 | self.send_data(temp2) 177 | j += 1 178 | 179 | self.send_command(0x12) 180 | epdconfig.delay_ms(100) 181 | self.ReadBusy() 182 | 183 | def Clear(self): 184 | self.send_command(0x10) 185 | for i in range(0, int(self.width / 4 * self.height)): 186 | for j in range(0, 4): 187 | self.send_data(0x33) 188 | self.send_command(0x12) 189 | self.ReadBusy() 190 | 191 | def sleep(self): 192 | self.send_command(0x02) # POWER_OFF 193 | self.ReadBusy() 194 | self.send_command(0x07) # DEEP_SLEEP 195 | self.send_data(0XA5) 196 | 197 | def Dev_exit(self): 198 | epdconfig.module_exit() 199 | 200 | ### END OF FILE ### 201 | 202 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5b_HD.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5bc_HD.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 880 36 | EPD_HEIGHT = 528 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(4) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | busy = epdconfig.digital_read(self.busy_pin) 71 | while(busy == 1): 72 | busy = epdconfig.digital_read(self.busy_pin) 73 | epdconfig.delay_ms(200) 74 | 75 | def init(self): 76 | if (epdconfig.module_init() != 0): 77 | return -1 78 | 79 | self.reset() 80 | 81 | self.send_command(0x12); #SWRESET 82 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 83 | 84 | self.send_command(0x46); # Auto Write RAM 85 | self.send_data(0xF7); 86 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 87 | 88 | self.send_command(0x47); # Auto Write RAM 89 | self.send_data(0xF7); 90 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 91 | 92 | self.send_command(0x0C); # Soft start setting 93 | self.send_data(0xAE); 94 | self.send_data(0xC7); 95 | self.send_data(0xC3); 96 | self.send_data(0xC0); 97 | self.send_data(0x40); 98 | 99 | self.send_command(0x01); # Set MUX as 527 100 | self.send_data(0xAF); 101 | self.send_data(0x02); 102 | self.send_data(0x01); 103 | 104 | self.send_command(0x11); # Data entry mode 105 | self.send_data(0x01); 106 | 107 | self.send_command(0x44); 108 | self.send_data(0x00); # RAM x address start at 0 109 | self.send_data(0x00); 110 | self.send_data(0x6F); # RAM x address end at 36Fh -> 879 111 | self.send_data(0x03); 112 | self.send_command(0x45); 113 | self.send_data(0xAF); # RAM y address start at 20Fh; 114 | self.send_data(0x02); 115 | self.send_data(0x00); # RAM y address end at 00h; 116 | self.send_data(0x00); 117 | 118 | self.send_command(0x3C); # VBD 119 | self.send_data(0x01); # LUT1, for white 120 | 121 | self.send_command(0x18); 122 | self.send_data(0X80); 123 | self.send_command(0x22); 124 | self.send_data(0XB1); #Load Temperature and waveform setting. 125 | self.send_command(0x20); 126 | self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal 127 | 128 | self.send_command(0x4E); 129 | self.send_data(0x00); 130 | self.send_data(0x00); 131 | self.send_command(0x4F); 132 | self.send_data(0xAF); 133 | self.send_data(0x02); 134 | 135 | return 0 136 | 137 | def getbuffer(self, image): 138 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 139 | buf = [0xFF] * (int(self.width/8) * self.height) 140 | image_monocolor = image.convert('1') 141 | imwidth, imheight = image_monocolor.size 142 | pixels = image_monocolor.load() 143 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 144 | if(imwidth == self.width and imheight == self.height): 145 | logging.debug("Horizontal") 146 | for y in range(imheight): 147 | for x in range(imwidth): 148 | # Set the bits for the column of pixels at the current position. 149 | if pixels[x, y] == 0: 150 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 151 | elif(imwidth == self.height and imheight == self.width): 152 | logging.debug("Vertical") 153 | for y in range(imheight): 154 | for x in range(imwidth): 155 | newx = y 156 | newy = self.height - x - 1 157 | if pixels[x, y] == 0: 158 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 159 | return buf 160 | 161 | def display(self, imageblack, imagered): 162 | self.send_command(0x4F); 163 | self.send_data(0xAf); 164 | 165 | self.send_command(0x24) 166 | for i in range(0, int(self.width * self.height / 8)): 167 | self.send_data(imageblack[i]); 168 | 169 | 170 | self.send_command(0x26) 171 | for i in range(0, int(self.width * self.height / 8)): 172 | self.send_data(~imagered[i]); 173 | 174 | self.send_command(0x22); 175 | self.send_data(0xC7); #Load LUT from MCU(0x32) 176 | self.send_command(0x20); 177 | epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! 178 | self.ReadBusy(); 179 | 180 | def Clear(self): 181 | self.send_command(0x4F); 182 | self.send_data(0xAf); 183 | 184 | self.send_command(0x24) 185 | for i in range(0, int(self.width * self.height / 8)): 186 | self.send_data(0xff); 187 | 188 | 189 | self.send_command(0x26) 190 | for i in range(0, int(self.width * self.height / 8)): 191 | self.send_data(0x00); 192 | 193 | self.send_command(0x22); 194 | self.send_data(0xC7); #Load LUT from MCU(0x32) 195 | self.send_command(0x20); 196 | epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! 197 | self.ReadBusy(); 198 | 199 | def sleep(self): 200 | self.send_command(0x10); #deep sleep 201 | self.send_data(0x01); 202 | 203 | def Dev_exit(self): 204 | epdconfig.module_exit() 205 | ### END OF FILE ### 206 | 207 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd7in5.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd7in5.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | 34 | # Display resolution 35 | EPD_WIDTH = 640 36 | EPD_HEIGHT = 384 37 | 38 | class EPD: 39 | def __init__(self): 40 | self.reset_pin = epdconfig.RST_PIN 41 | self.dc_pin = epdconfig.DC_PIN 42 | self.busy_pin = epdconfig.BUSY_PIN 43 | self.cs_pin = epdconfig.CS_PIN 44 | self.width = EPD_WIDTH 45 | self.height = EPD_HEIGHT 46 | 47 | # Hardware reset 48 | def reset(self): 49 | epdconfig.digital_write(self.reset_pin, 1) 50 | epdconfig.delay_ms(200) 51 | epdconfig.digital_write(self.reset_pin, 0) 52 | epdconfig.delay_ms(5) 53 | epdconfig.digital_write(self.reset_pin, 1) 54 | epdconfig.delay_ms(200) 55 | 56 | def send_command(self, command): 57 | epdconfig.digital_write(self.dc_pin, 0) 58 | epdconfig.digital_write(self.cs_pin, 0) 59 | epdconfig.spi_writebyte([command]) 60 | epdconfig.digital_write(self.cs_pin, 1) 61 | 62 | def send_data(self, data): 63 | epdconfig.digital_write(self.dc_pin, 1) 64 | epdconfig.digital_write(self.cs_pin, 0) 65 | epdconfig.spi_writebyte([data]) 66 | epdconfig.digital_write(self.cs_pin, 1) 67 | 68 | def ReadBusy(self): 69 | logging.debug("e-Paper busy") 70 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 71 | epdconfig.delay_ms(100) 72 | logging.debug("e-Paper busy release") 73 | 74 | def init(self): 75 | if (epdconfig.module_init() != 0): 76 | return -1 77 | # EPD hardware init start 78 | self.reset() 79 | 80 | self.send_command(0x01) # POWER_SETTING 81 | self.send_data(0x37) 82 | self.send_data(0x00) 83 | 84 | self.send_command(0x00) # PANEL_SETTING 85 | self.send_data(0xCF) 86 | self.send_data(0x08) 87 | 88 | self.send_command(0x06) # BOOSTER_SOFT_START 89 | self.send_data(0xc7) 90 | self.send_data(0xcc) 91 | self.send_data(0x28) 92 | 93 | self.send_command(0x04) # POWER_ON 94 | self.ReadBusy() 95 | 96 | self.send_command(0x30) # PLL_CONTROL 97 | self.send_data(0x3c) 98 | 99 | self.send_command(0x41) # TEMPERATURE_CALIBRATION 100 | self.send_data(0x00) 101 | 102 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 103 | self.send_data(0x77) 104 | 105 | self.send_command(0x60) # TCON_SETTING 106 | self.send_data(0x22) 107 | 108 | self.send_command(0x61) # TCON_RESOLUTION 109 | self.send_data(EPD_WIDTH >> 8) #source 640 110 | self.send_data(EPD_WIDTH & 0xff) 111 | self.send_data(EPD_HEIGHT >> 8) #gate 384 112 | self.send_data(EPD_HEIGHT & 0xff) 113 | 114 | self.send_command(0x82) # VCM_DC_SETTING 115 | self.send_data(0x1E) # decide by LUT file 116 | 117 | self.send_command(0xe5) # FLASH MODE 118 | self.send_data(0x03) 119 | 120 | # EPD hardware init end 121 | return 0 122 | 123 | def getbuffer(self, image): 124 | logging.debug("1234") 125 | buf = [0x00] * int(self.width * self.height / 4) 126 | image_monocolor = image.convert('1') 127 | imwidth, imheight = image_monocolor.size 128 | pixels = image_monocolor.load() 129 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 130 | if(imwidth == self.width and imheight == self.height): 131 | for y in range(imheight): 132 | for x in range(imwidth): 133 | # Set the bits for the column of pixels at the current position. 134 | if pixels[x, y] < 64: # black 135 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 136 | elif pixels[x, y] < 192: # convert gray to red 137 | buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2)) 138 | buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) 139 | else: # white 140 | buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) 141 | elif(imwidth == self.height and imheight == self.width): 142 | for y in range(imheight): 143 | for x in range(imwidth): 144 | newx = y 145 | newy = self.height - x - 1 146 | if pixels[x, y] < 64: # black 147 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 148 | elif pixels[x, y] < 192: # convert gray to red 149 | buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) 150 | buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) 151 | else: # white 152 | buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) 153 | return buf 154 | 155 | def display(self, image): 156 | self.send_command(0x10) 157 | for i in range(0, int(self.width / 4 * self.height)): 158 | temp1 = image[i] 159 | j = 0 160 | while (j < 4): 161 | if ((temp1 & 0xC0) == 0xC0): 162 | temp2 = 0x03 163 | elif ((temp1 & 0xC0) == 0x00): 164 | temp2 = 0x00 165 | else: 166 | temp2 = 0x04 167 | temp2 = (temp2 << 4) & 0xFF 168 | temp1 = (temp1 << 2) & 0xFF 169 | j += 1 170 | if((temp1 & 0xC0) == 0xC0): 171 | temp2 |= 0x03 172 | elif ((temp1 & 0xC0) == 0x00): 173 | temp2 |= 0x00 174 | else: 175 | temp2 |= 0x04 176 | temp1 = (temp1 << 2) & 0xFF 177 | self.send_data(temp2) 178 | j += 1 179 | 180 | self.send_command(0x12) 181 | epdconfig.delay_ms(100) 182 | self.ReadBusy() 183 | 184 | def Clear(self): 185 | self.send_command(0x10) 186 | for i in range(0, int(self.width / 4 * self.height)): 187 | for j in range(0, 4): 188 | self.send_data(0x33) 189 | 190 | self.send_command(0x12) 191 | self.ReadBusy() 192 | 193 | def sleep(self): 194 | self.send_command(0x02) # POWER_OFF 195 | self.ReadBusy() 196 | 197 | self.send_command(0x07) # DEEP_SLEEP 198 | self.send_data(0XA5) 199 | 200 | def Dev_exit(self): 201 | epdconfig.module_exit() 202 | ### END OF FILE ### 203 | 204 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd1in54_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 200 35 | EPD_HEIGHT = 200 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | while(epdconfig.digital_read(self.busy_pin) == 1): 70 | epdconfig.delay_ms(100) 71 | logging.debug("e-Paper busy release") 72 | 73 | def TurnOnDisplay(self): 74 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 75 | self.send_data(0xF7) 76 | self.send_command(0x20) # MASTER_ACTIVATION 77 | 78 | self.ReadBusy() 79 | 80 | def TurnOnDisplayPart(self): 81 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 82 | self.send_data(0xFF) 83 | self.send_command(0x20) # MASTER_ACTIVATION 84 | 85 | self.ReadBusy() 86 | 87 | def init(self): 88 | if (epdconfig.module_init() != 0): 89 | return -1 90 | 91 | # EPD hardware init start 92 | self.reset() 93 | 94 | self.ReadBusy() 95 | self.send_command(0x12) # SWRESET 96 | self.ReadBusy() 97 | 98 | self.send_command(0x01) # DRIVER_OUTPUT_CONTROL 99 | self.send_data(0xC7) # (EPD_HEIGHT - 1) & 0xFF 100 | self.send_data(0x00) # ((EPD_HEIGHT - 1) >> 8) & 0xFF 101 | self.send_data(0x01) # GD = 0 SM = 0 TB = 0 102 | 103 | self.send_command(0x11) # data entry mode 104 | self.send_data(0x01) 105 | 106 | self.send_command(0x44) # set Ram-X address start/end position 107 | self.send_data(0x00) 108 | self.send_data(0x18) # 0x0C-->(18+1)*8=200 109 | 110 | self.send_command(0x45) # set Ram-Y address start/end position 111 | self.send_data(0xC7) # 0xC7-->(199+1)=200 112 | self.send_data(0x00) 113 | self.send_data(0x00) 114 | self.send_data(0x00) 115 | 116 | self.send_command(0x3C) # BorderWavefrom 117 | self.send_data(0x01) 118 | 119 | self.send_command(0x18) 120 | self.send_data(0x80) 121 | 122 | self.send_command(0x22) # #Load Temperature and waveform setting. 123 | self.send_data(0XB1) 124 | self.send_command(0x20) 125 | 126 | self.send_command(0x4E) # set RAM x address count to 0; 127 | self.send_data(0x00) 128 | self.send_command(0x4F) # set RAM y address count to 0X199; 129 | self.send_data(0xC7) 130 | self.send_data(0x00) 131 | 132 | self.ReadBusy() 133 | 134 | def Clear(self, color): 135 | self.send_command(0x24) 136 | for j in range(0, self.height): 137 | for i in range(0, int(self.width / 8)): 138 | self.send_data(color) 139 | 140 | self.TurnOnDisplay() 141 | 142 | def getbuffer(self, image): 143 | buf = [0xFF] * (int(self.width/8) * self.height) 144 | image_monocolor = image.convert('1') 145 | imwidth, imheight = image_monocolor.size 146 | pixels = image_monocolor.load() 147 | if(imwidth == self.width and imheight == self.height): 148 | logging.debug("Horizontal") 149 | for y in range(imheight): 150 | for x in range(imwidth): 151 | # Set the bits for the column of pixels at the current position. 152 | if pixels[x, y] == 0: 153 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 154 | elif(imwidth == self.height and imheight == self.width): 155 | logging.debug("Vertical") 156 | for y in range(imheight): 157 | for x in range(imwidth): 158 | newx = y 159 | newy = self.height - x - 1 160 | if pixels[x, y] == 0: 161 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 162 | return buf 163 | 164 | def display(self, image): 165 | if (image == None): 166 | return 167 | 168 | self.send_command(0x24) 169 | for j in range(0, self.height): 170 | for i in range(0, int(self.width / 8)): 171 | self.send_data(image[i + j * int(self.width / 8)]) 172 | self.TurnOnDisplay() 173 | 174 | def displayPartBaseImage(self, image): 175 | if (image == None): 176 | return 177 | 178 | self.send_command(0x24) 179 | for j in range(0, self.height): 180 | for i in range(0, int(self.width / 8)): 181 | self.send_data(image[i + j * int(self.width / 8)]) 182 | 183 | self.send_command(0x26) 184 | for j in range(0, self.height): 185 | for i in range(0, int(self.width / 8)): 186 | self.send_data(image[i + j * int(self.width / 8)]) 187 | 188 | self.TurnOnDisplayPart() 189 | 190 | def displayPart(self, image): 191 | if (image == None): 192 | return 193 | 194 | epdconfig.digital_write(self.reset_pin, 0) 195 | epdconfig.delay_ms(10) 196 | epdconfig.digital_write(self.reset_pin, 1) 197 | epdconfig.delay_ms(10) 198 | 199 | self.send_command(0x3c) 200 | self.send_data(0x80) 201 | 202 | self.send_command(0x24) 203 | for j in range(0, self.height): 204 | for i in range(0, int(self.width / 8)): 205 | self.send_data(image[i + j * int(self.width / 8)]) 206 | 207 | self.TurnOnDisplayPart() 208 | 209 | def sleep(self): 210 | self.send_command(0x10) # DEEP_SLEEP_MODE 211 | self.send_data(0x01) 212 | 213 | def Dev_exit(self): 214 | epdconfig.module_exit() 215 | 216 | ### END OF FILE ### 217 | 218 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in9.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 128 35 | EPD_HEIGHT = 296 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | lut_full_update = [ 47 | 0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 52 | ] 53 | 54 | lut_partial_update = [ 55 | 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 56 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 60 | ] 61 | 62 | # Hardware reset 63 | def reset(self): 64 | epdconfig.digital_write(self.reset_pin, 1) 65 | epdconfig.delay_ms(200) 66 | epdconfig.digital_write(self.reset_pin, 0) 67 | epdconfig.delay_ms(5) 68 | epdconfig.digital_write(self.reset_pin, 1) 69 | epdconfig.delay_ms(200) 70 | 71 | def send_command(self, command): 72 | epdconfig.digital_write(self.dc_pin, 0) 73 | epdconfig.digital_write(self.cs_pin, 0) 74 | epdconfig.spi_writebyte([command]) 75 | epdconfig.digital_write(self.cs_pin, 1) 76 | 77 | def send_data(self, data): 78 | epdconfig.digital_write(self.dc_pin, 1) 79 | epdconfig.digital_write(self.cs_pin, 0) 80 | epdconfig.spi_writebyte([data]) 81 | epdconfig.digital_write(self.cs_pin, 1) 82 | 83 | def ReadBusy(self): 84 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 85 | epdconfig.delay_ms(200) 86 | 87 | def TurnOnDisplay(self): 88 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 89 | self.send_data(0xC4) 90 | self.send_command(0x20) # MASTER_ACTIVATION 91 | self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE 92 | 93 | logging.debug("e-Paper busy") 94 | self.ReadBusy() 95 | logging.debug("e-Paper busy release") 96 | 97 | def SetWindow(self, x_start, y_start, x_end, y_end): 98 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 99 | # x point must be the multiple of 8 or the last 3 bits will be ignored 100 | self.send_data((x_start >> 3) & 0xFF) 101 | self.send_data((x_end >> 3) & 0xFF) 102 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 103 | self.send_data(y_start & 0xFF) 104 | self.send_data((y_start >> 8) & 0xFF) 105 | self.send_data(y_end & 0xFF) 106 | self.send_data((y_end >> 8) & 0xFF) 107 | 108 | def SetCursor(self, x, y): 109 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 110 | # x point must be the multiple of 8 or the last 3 bits will be ignored 111 | self.send_data((x >> 3) & 0xFF) 112 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 113 | self.send_data(y & 0xFF) 114 | self.send_data((y >> 8) & 0xFF) 115 | self.ReadBusy() 116 | 117 | def init(self, lut): 118 | if (epdconfig.module_init() != 0): 119 | return -1 120 | # EPD hardware init start 121 | self.reset() 122 | 123 | self.send_command(0x01) # DRIVER_OUTPUT_CONTROL 124 | self.send_data((EPD_HEIGHT - 1) & 0xFF) 125 | self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF) 126 | self.send_data(0x00) # GD = 0 SM = 0 TB = 0 127 | 128 | self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL 129 | self.send_data(0xD7) 130 | self.send_data(0xD6) 131 | self.send_data(0x9D) 132 | 133 | self.send_command(0x2C) # WRITE_VCOM_REGISTER 134 | self.send_data(0xA8) # VCOM 7C 135 | 136 | self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD 137 | self.send_data(0x1A) # 4 dummy lines per gate 138 | 139 | self.send_command(0x3B) # SET_GATE_TIME 140 | self.send_data(0x08) # 2us per line 141 | 142 | self.send_command(0x11) # DATA_ENTRY_MODE_SETTING 143 | self.send_data(0x03) # X increment Y increment 144 | 145 | self.send_command(0x32) # WRITE_LUT_REGISTER 146 | for i in range(0, len(lut)): 147 | self.send_data(lut[i]) 148 | # EPD hardware init end 149 | return 0 150 | 151 | def getbuffer(self, image): 152 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 153 | buf = [0xFF] * (int(self.width/8) * self.height) 154 | image_monocolor = image.convert('1') 155 | imwidth, imheight = image_monocolor.size 156 | pixels = image_monocolor.load() 157 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 158 | if(imwidth == self.width and imheight == self.height): 159 | logging.debug("Vertical") 160 | for y in range(imheight): 161 | for x in range(imwidth): 162 | # Set the bits for the column of pixels at the current position. 163 | if pixels[x, y] == 0: 164 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 165 | elif(imwidth == self.height and imheight == self.width): 166 | logging.debug("Horizontal") 167 | for y in range(imheight): 168 | for x in range(imwidth): 169 | newx = y 170 | newy = self.height - x - 1 171 | if pixels[x, y] == 0: 172 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 173 | return buf 174 | 175 | def display(self, image): 176 | if (image == None): 177 | return 178 | self.SetWindow(0, 0, self.width - 1, self.height - 1) 179 | for j in range(0, self.height): 180 | self.SetCursor(0, j) 181 | self.send_command(0x24) # WRITE_RAM 182 | for i in range(0, int(self.width / 8)): 183 | self.send_data(image[i + j * int(self.width / 8)]) 184 | self.TurnOnDisplay() 185 | 186 | def Clear(self, color): 187 | self.SetWindow(0, 0, self.width - 1, self.height - 1) 188 | for j in range(0, self.height): 189 | self.SetCursor(0, j) 190 | self.send_command(0x24) # WRITE_RAM 191 | for i in range(0, int(self.width / 8)): 192 | self.send_data(color) 193 | self.TurnOnDisplay() 194 | 195 | def sleep(self): 196 | self.send_command(0x10) # DEEP_SLEEP_MODE 197 | self.send_data(0x01) 198 | 199 | def Dev_exit(self): 200 | epdconfig.module_exit() 201 | ### END OF FILE ### 202 | 203 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in66.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in66.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-07-22 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 152 35 | EPD_HEIGHT = 296 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | WF_PARTIAL = [ 47 | 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 48 | 0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 49 | 0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x00,0x00, 50 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00, 51 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 52 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 53 | 0x0A,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x00, 54 | 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 55 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 58 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 59 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 60 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 61 | 0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22, 62 | 0x00,0x00,0x00,0x22,0x17,0x41,0xB0,0x32,0x36, 63 | ] 64 | 65 | 66 | # Hardware reset 67 | def reset(self): 68 | epdconfig.digital_write(self.reset_pin, 1) 69 | epdconfig.delay_ms(200) 70 | epdconfig.digital_write(self.reset_pin, 0) 71 | epdconfig.delay_ms(5) 72 | epdconfig.digital_write(self.reset_pin, 1) 73 | epdconfig.delay_ms(200) 74 | 75 | 76 | def send_command(self, command): 77 | epdconfig.digital_write(self.dc_pin, 0) 78 | epdconfig.digital_write(self.cs_pin, 0) 79 | epdconfig.spi_writebyte([command]) 80 | epdconfig.digital_write(self.cs_pin, 1) 81 | 82 | 83 | def send_data(self, data): 84 | epdconfig.digital_write(self.dc_pin, 1) 85 | epdconfig.digital_write(self.cs_pin, 0) 86 | epdconfig.spi_writebyte([data]) 87 | epdconfig.digital_write(self.cs_pin, 1) 88 | 89 | 90 | def ReadBusy(self): 91 | logging.debug("e-Paper busy") 92 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 93 | epdconfig.delay_ms(200) 94 | logging.debug("e-Paper busy release") 95 | 96 | 97 | def init(self, mode): 98 | if (epdconfig.module_init() != 0): 99 | return -1 100 | # EPD hardware init start 101 | self.reset() 102 | 103 | self.send_command(0x12) 104 | epdconfig.delay_ms(300) 105 | self.ReadBusy() 106 | 107 | self.send_command(0x11) # setting gaet number 108 | self.send_data(0x03) 109 | self.send_command(0x44) # set gate voltage 110 | self.send_data(0x01) 111 | self.send_data(0x13) 112 | self.send_command(0x45) # set source voltage 113 | self.send_data(0x0) 114 | self.send_data(0x0) 115 | self.send_data(0x28) 116 | self.send_data(0x01) 117 | 118 | if(mode == 0): #full 119 | self.send_command(0x3C) 120 | self.send_data(0x01) 121 | 122 | elif(mode == 1): #partial 123 | self.load_lut(self.WF_PARTIAL) 124 | self.send_command(0x37) # set display option, these setting turn on previous function 125 | self.send_data(0x00) 126 | self.send_data(0x00) 127 | self.send_data(0x00) 128 | self.send_data(0x00) 129 | self.send_data(0x00) 130 | self.send_data(0x40) 131 | self.send_data(0x00) 132 | self.send_data(0x00) 133 | self.send_data(0x00) 134 | self.send_data(0x00) 135 | 136 | self.send_command(0x3C) 137 | self.send_data(0x80) 138 | 139 | self.send_command(0x22) 140 | self.send_data(0xcf) 141 | 142 | self.send_command(0x20) 143 | self.ReadBusy() 144 | 145 | else: 146 | logging.debug("There is no such mode") 147 | 148 | return 0 149 | 150 | 151 | def load_lut(self, lut): 152 | self.send_command(0x32) 153 | for i in range(0, 153): 154 | self.send_data(lut[i]) 155 | 156 | 157 | def turnon_display(self): 158 | self.send_command(0x20) 159 | self.ReadBusy() 160 | 161 | def getbuffer(self, image): 162 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 163 | buf = [0xFF] * (int(self.width/8) * self.height) 164 | image_monocolor = image.convert('1') 165 | imwidth, imheight = image_monocolor.size 166 | pixels = image_monocolor.load() 167 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 168 | if(imwidth == self.width and imheight == self.height): 169 | logging.debug("Vertical") 170 | for y in range(imheight): 171 | for x in range(imwidth): 172 | # Set the bits for the column of pixels at the current position. 173 | if pixels[x, y] == 0: 174 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 175 | elif(imwidth == self.height and imheight == self.width): 176 | logging.debug("Horizontal") 177 | for y in range(imheight): 178 | for x in range(imwidth): 179 | newx = y 180 | newy = self.height - x - 1 181 | if pixels[x, y] == 0: 182 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 183 | return buf 184 | 185 | 186 | def display(self, image): 187 | if (image == None): 188 | return 189 | 190 | self.send_command(0x4E) 191 | self.send_data(0x01) 192 | self.send_command(0x4F) 193 | self.send_data(0x27) 194 | self.send_data(0x01) 195 | 196 | self.send_command(0x24) 197 | for j in range(0, self.height): 198 | for i in range(0, int(self.width / 8)): 199 | self.send_data(image[i + j * int(self.width / 8)]) 200 | 201 | self.turnon_display() 202 | 203 | 204 | def Clear(self): 205 | self.send_command(0x4E) 206 | self.send_data(0x01) 207 | self.send_command(0x4F) 208 | self.send_data(0x27) 209 | self.send_data(0x01) 210 | 211 | self.send_command(0x24) 212 | for j in range(0, self.height): 213 | for i in range(0, int(self.width / 8)): 214 | self.send_data(0xff) 215 | 216 | self.send_command(0x26) 217 | for j in range(0, self.height): 218 | for i in range(0, int(self.width / 8)): 219 | self.send_data(0xff) 220 | 221 | self.turnon_display() 222 | 223 | 224 | def sleep(self): 225 | self.send_command(0X10) # DEEP_SLEEP_MODE 226 | self.send_data(0x01) 227 | 228 | def Dev_exit(self): 229 | epdconfig.module_exit() 230 | 231 | ### END OF FILE ### 232 | 233 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in13.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in13.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | 31 | import logging 32 | from . import epdconfig 33 | import numpy as np 34 | 35 | # Display resolution 36 | EPD_WIDTH = 122 37 | EPD_HEIGHT = 250 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | 48 | lut_full_update = [ 49 | 0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 52 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 53 | ] 54 | 55 | lut_partial_update = [ 56 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 60 | ] 61 | 62 | # Hardware reset 63 | def reset(self): 64 | epdconfig.digital_write(self.reset_pin, 1) 65 | epdconfig.delay_ms(200) 66 | epdconfig.digital_write(self.reset_pin, 0) 67 | epdconfig.delay_ms(5) 68 | epdconfig.digital_write(self.reset_pin, 1) 69 | epdconfig.delay_ms(200) 70 | 71 | def send_command(self, command): 72 | epdconfig.digital_write(self.dc_pin, 0) 73 | epdconfig.digital_write(self.cs_pin, 0) 74 | epdconfig.spi_writebyte([command]) 75 | epdconfig.digital_write(self.cs_pin, 1) 76 | 77 | def send_data(self, data): 78 | epdconfig.digital_write(self.dc_pin, 1) 79 | epdconfig.digital_write(self.cs_pin, 0) 80 | epdconfig.spi_writebyte([data]) 81 | epdconfig.digital_write(self.cs_pin, 1) 82 | 83 | def ReadBusy(self): 84 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 85 | epdconfig.delay_ms(100) 86 | 87 | def TurnOnDisplay(self): 88 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 89 | self.send_data(0xC4) 90 | self.send_command(0x20) # MASTER_ACTIVATION 91 | self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE 92 | 93 | logging.debug("e-Paper busy") 94 | self.ReadBusy() 95 | logging.debug("e-Paper busy release") 96 | 97 | def init(self, lut): 98 | if (epdconfig.module_init() != 0): 99 | return -1 100 | # EPD hardware init start 101 | self.reset() 102 | self.send_command(0x01) # DRIVER_OUTPUT_CONTROL 103 | self.send_data((EPD_HEIGHT - 1) & 0xFF) 104 | self.send_data(((EPD_HEIGHT - 1) >> 8) & 0xFF) 105 | self.send_data(0x00) # GD = 0 SM = 0 TB = 0 106 | 107 | self.send_command(0x0C) # BOOSTER_SOFT_START_CONTROL 108 | self.send_data(0xD7) 109 | self.send_data(0xD6) 110 | self.send_data(0x9D) 111 | 112 | self.send_command(0x2C) # WRITE_VCOM_REGISTER 113 | self.send_data(0xA8) # VCOM 7C 114 | 115 | self.send_command(0x3A) # SET_DUMMY_LINE_PERIOD 116 | self.send_data(0x1A) # 4 dummy lines per gate 117 | 118 | self.send_command(0x3B) # SET_GATE_TIME 119 | self.send_data(0x08) # 2us per line 120 | 121 | self.send_command(0X3C) # BORDER_WAVEFORM_CONTROL 122 | self.send_data(0x03) 123 | 124 | self.send_command(0X11) # DATA_ENTRY_MODE_SETTING 125 | self.send_data(0x03) # X increment; Y increment 126 | 127 | # WRITE_LUT_REGISTER 128 | self.send_command(0x32) 129 | for count in range(30): 130 | self.send_data(lut[count]) 131 | 132 | return 0 133 | 134 | ## 135 | # @brief: specify the memory area for data R/W 136 | ## 137 | def SetWindows(self, x_start, y_start, x_end, y_end): 138 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 139 | self.send_data((x_start >> 3) & 0xFF) 140 | self.send_data((x_end >> 3) & 0xFF) 141 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 142 | self.send_data(y_start & 0xFF) 143 | self.send_data((y_start >> 8) & 0xFF) 144 | self.send_data(y_end & 0xFF) 145 | self.send_data((y_end >> 8) & 0xFF) 146 | 147 | ## 148 | # @brief: specify the start point for data R/W 149 | ## 150 | def SetCursor(self, x, y): 151 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 152 | # x point must be the multiple of 8 or the last 3 bits will be ignored 153 | self.send_data((x >> 3) & 0xFF) 154 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 155 | self.send_data(y & 0xFF) 156 | self.send_data((y >> 8) & 0xFF) 157 | self.ReadBusy() 158 | 159 | def getbuffer(self, image): 160 | if self.width%8 == 0: 161 | linewidth = int(self.width/8) 162 | else: 163 | linewidth = int(self.width/8) + 1 164 | 165 | buf = [0xFF] * (linewidth * self.height) 166 | image_monocolor = image.convert('1') 167 | imwidth, imheight = image_monocolor.size 168 | pixels = image_monocolor.load() 169 | 170 | if(imwidth == self.width and imheight == self.height): 171 | logging.debug("Vertical") 172 | for y in range(imheight): 173 | for x in range(imwidth): 174 | if pixels[x, y] == 0: 175 | # x = imwidth - x 176 | buf[int(x / 8) + y * linewidth] &= ~(0x80 >> (x % 8)) 177 | elif(imwidth == self.height and imheight == self.width): 178 | logging.debug("Horizontal") 179 | for y in range(imheight): 180 | for x in range(imwidth): 181 | newx = y 182 | newy = self.height - x - 1 183 | if pixels[x, y] == 0: 184 | # newy = imwidth - newy - 1 185 | buf[int(newx / 8) + newy*linewidth] &= ~(0x80 >> (y % 8)) 186 | return buf 187 | 188 | 189 | def display(self, image): 190 | if self.width%8 == 0: 191 | linewidth = int(self.width/8) 192 | else: 193 | linewidth = int(self.width/8) + 1 194 | 195 | self.SetWindows(0, 0, self.width, self.height); 196 | for j in range(0, self.height): 197 | self.SetCursor(0, j); 198 | self.send_command(0x24); 199 | for i in range(0, linewidth): 200 | self.send_data(image[i + j * linewidth]) 201 | self.TurnOnDisplay() 202 | 203 | def Clear(self, color): 204 | if self.width%8 == 0: 205 | linewidth = int(self.width/8) 206 | else: 207 | linewidth = int(self.width/8) + 1 208 | 209 | self.SetWindows(0, 0, self.width, self.height); 210 | for j in range(0, self.height): 211 | self.SetCursor(0, j); 212 | self.send_command(0x24); 213 | for i in range(0, linewidth): 214 | self.send_data(color) 215 | self.TurnOnDisplay() 216 | 217 | def sleep(self): 218 | self.send_command(0x10) #enter deep sleep 219 | self.send_data(0x01) 220 | epdconfig.delay_ms(100) 221 | 222 | def Dev_exit(self): 223 | epdconfig.module_exit() 224 | 225 | ### END OF FILE ### 226 | 227 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd2in9_V2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd2in9_V2.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V1.0 8 | # * | Date : 2020-10-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 128 35 | EPD_HEIGHT = 296 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | # Hardware reset 47 | def reset(self): 48 | epdconfig.digital_write(self.reset_pin, 1) 49 | epdconfig.delay_ms(200) 50 | epdconfig.digital_write(self.reset_pin, 0) 51 | epdconfig.delay_ms(5) 52 | epdconfig.digital_write(self.reset_pin, 1) 53 | epdconfig.delay_ms(200) 54 | 55 | def send_command(self, command): 56 | epdconfig.digital_write(self.dc_pin, 0) 57 | epdconfig.digital_write(self.cs_pin, 0) 58 | epdconfig.spi_writebyte([command]) 59 | epdconfig.digital_write(self.cs_pin, 1) 60 | 61 | def send_data(self, data): 62 | epdconfig.digital_write(self.dc_pin, 1) 63 | epdconfig.digital_write(self.cs_pin, 0) 64 | epdconfig.spi_writebyte([data]) 65 | epdconfig.digital_write(self.cs_pin, 1) 66 | 67 | def ReadBusy(self): 68 | logging.debug("e-Paper busy") 69 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 70 | epdconfig.delay_ms(200) 71 | logging.debug("e-Paper busy release") 72 | 73 | def TurnOnDisplay(self): 74 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 75 | self.send_data(0xF7) 76 | self.send_command(0x20) # MASTER_ACTIVATION 77 | self.ReadBusy() 78 | 79 | def TurnOnDisplay_Partial(self): 80 | self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2 81 | self.send_data(0xFF) 82 | self.send_command(0x20) # MASTER_ACTIVATION 83 | self.ReadBusy() 84 | 85 | def SetWindow(self, x_start, y_start, x_end, y_end): 86 | self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION 87 | # x point must be the multiple of 8 or the last 3 bits will be ignored 88 | self.send_data((x_start>>3) & 0xFF) 89 | self.send_data((x_end>>3) & 0xFF) 90 | self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION 91 | self.send_data(y_start & 0xFF) 92 | self.send_data((y_start >> 8) & 0xFF) 93 | self.send_data(y_end & 0xFF) 94 | self.send_data((y_end >> 8) & 0xFF) 95 | 96 | def SetCursor(self, x, y): 97 | self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER 98 | # x point must be the multiple of 8 or the last 3 bits will be ignored 99 | self.send_data(x & 0xFF) 100 | 101 | self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER 102 | self.send_data(y & 0xFF) 103 | self.send_data((y >> 8) & 0xFF) 104 | self.ReadBusy() 105 | 106 | def init(self): 107 | if (epdconfig.module_init() != 0): 108 | return -1 109 | # EPD hardware init start 110 | self.reset() 111 | 112 | self.ReadBusy(); 113 | self.send_command(0x12); #SWRESET 114 | self.ReadBusy(); 115 | 116 | self.send_command(0x01); #Driver output control 117 | self.send_data(0x27); 118 | self.send_data(0x01); 119 | self.send_data(0x00); 120 | 121 | self.send_command(0x11); #data entry mode 122 | self.send_data(0x03); 123 | 124 | self.SetWindow(0, 0, self.width-1, self.height-1); 125 | 126 | self.send_command(0x3C); #BorderWavefrom 127 | self.send_data(0x05); 128 | 129 | self.send_command(0x21); # Display update control 130 | self.send_data(0x00); 131 | self.send_data(0x80); 132 | 133 | self.send_command(0x18); #Read built-in temperature sensor 134 | self.send_data(0x80); 135 | 136 | self.SetCursor(0, 0); 137 | self.ReadBusy(); 138 | # EPD hardware init end 139 | return 0 140 | 141 | def getbuffer(self, image): 142 | # logging.debug("bufsiz = ",int(self.width/8) * self.height) 143 | buf = [0xFF] * (int(self.width/8) * self.height) 144 | image_monocolor = image.convert('1') 145 | imwidth, imheight = image_monocolor.size 146 | pixels = image_monocolor.load() 147 | # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) 148 | if(imwidth == self.width and imheight == self.height): 149 | logging.debug("Vertical") 150 | for y in range(imheight): 151 | for x in range(imwidth): 152 | # Set the bits for the column of pixels at the current position. 153 | if pixels[x, y] == 0: 154 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 155 | elif(imwidth == self.height and imheight == self.width): 156 | logging.debug("Horizontal") 157 | for y in range(imheight): 158 | for x in range(imwidth): 159 | newx = y 160 | newy = self.height - x - 1 161 | if pixels[x, y] == 0: 162 | buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) 163 | return buf 164 | 165 | def display(self, image): 166 | if (image == None): 167 | return 168 | self.send_command(0x24) # WRITE_RAM 169 | for j in range(0, self.height): 170 | for i in range(0, int(self.width / 8)): 171 | self.send_data(image[i + j * int(self.width / 8)]) 172 | self.TurnOnDisplay() 173 | 174 | def display_Base(self, image): 175 | if (image == None): 176 | return 177 | 178 | self.send_command(0x24) # WRITE_RAM 179 | for j in range(0, self.height): 180 | for i in range(0, int(self.width / 8)): 181 | self.send_data(image[i + j * int(self.width / 8)]) 182 | 183 | self.send_command(0x26) # WRITE_RAM 184 | for j in range(0, self.height): 185 | for i in range(0, int(self.width / 8)): 186 | self.send_data(image[i + j * int(self.width / 8)]) 187 | 188 | self.TurnOnDisplay() 189 | 190 | def display_Partial(self, image): 191 | if (image == None): 192 | return 193 | 194 | epdconfig.digital_write(self.reset_pin, 0) 195 | epdconfig.delay_ms(5) 196 | epdconfig.digital_write(self.reset_pin, 1) 197 | epdconfig.delay_ms(10) 198 | 199 | self.send_command(0x3C); #BorderWavefrom 200 | self.send_data(0x80); 201 | 202 | self.SetWindow(0, 0, self.width - 1, self.height - 1) 203 | self.SetCursor(0, 0) 204 | self.send_command(0x24) # WRITE_RAM 205 | for j in range(0, self.height): 206 | for i in range(0, int(self.width / 8)): 207 | self.send_data(image[i + j * int(self.width / 8)]) 208 | self.TurnOnDisplay_Partial() 209 | 210 | def Clear(self, color): 211 | self.send_command(0x24) # WRITE_RAM 212 | for j in range(0, self.height): 213 | for i in range(0, int(self.width / 8)): 214 | self.send_data(color) 215 | self.TurnOnDisplay() 216 | 217 | def sleep(self): 218 | self.send_command(0x10) # DEEP_SLEEP_MODE 219 | self.send_data(0x01) 220 | 221 | def Dev_exit(self): 222 | epdconfig.module_exit() 223 | ### END OF FILE ### 224 | 225 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd1in54b.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # * | File : epd1in54b.py 3 | # * | Author : Waveshare team 4 | # * | Function : Electronic paper driver 5 | # * | Info : 6 | # *---------------- 7 | # * | This version: V4.0 8 | # * | Date : 2019-06-20 9 | # # | Info : python demo 10 | # ----------------------------------------------------------------------------- 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documnetation files (the "Software"), to deal 13 | # in the Software without restriction, including without limitation the rights 14 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | # copies of the Software, and to permit persons to whom the Software is 16 | # furished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | # THE SOFTWARE. 28 | # 29 | 30 | import logging 31 | from . import epdconfig 32 | 33 | # Display resolution 34 | EPD_WIDTH = 200 35 | EPD_HEIGHT = 200 36 | 37 | class EPD: 38 | def __init__(self): 39 | self.reset_pin = epdconfig.RST_PIN 40 | self.dc_pin = epdconfig.DC_PIN 41 | self.busy_pin = epdconfig.BUSY_PIN 42 | self.cs_pin = epdconfig.CS_PIN 43 | self.width = EPD_WIDTH 44 | self.height = EPD_HEIGHT 45 | 46 | lut_vcom0 = [0x0E, 0x14, 0x01, 0x0A, 0x06, 0x04, 0x0A, 0x0A, 0x0F, 0x03, 0x03, 0x0C, 0x06, 0x0A, 0x00] 47 | lut_w = [0x0E, 0x14, 0x01, 0x0A, 0x46, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x86, 0x0A, 0x04] 48 | lut_b = [0x0E, 0x14, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x4A, 0x04] 49 | lut_g1 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] 50 | lut_g2 = [0x8E, 0x94, 0x01, 0x8A, 0x06, 0x04, 0x8A, 0x4A, 0x0F, 0x83, 0x43, 0x0C, 0x06, 0x0A, 0x04] 51 | lut_vcom1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 52 | lut_red0 = [0x83, 0x5D, 0x01, 0x81, 0x48, 0x23, 0x77, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 53 | lut_red1 = [0x03, 0x1D, 0x01, 0x01, 0x08, 0x23, 0x37, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 54 | 55 | # Hardware reset 56 | def reset(self): 57 | epdconfig.digital_write(self.reset_pin, 1) 58 | epdconfig.delay_ms(200) 59 | epdconfig.digital_write(self.reset_pin, 0) # module reset 60 | epdconfig.delay_ms(5) 61 | epdconfig.digital_write(self.reset_pin, 1) 62 | epdconfig.delay_ms(200) 63 | 64 | def send_command(self, command): 65 | epdconfig.digital_write(self.dc_pin, 0) 66 | epdconfig.digital_write(self.cs_pin, 0) 67 | epdconfig.spi_writebyte([command]) 68 | epdconfig.digital_write(self.cs_pin, 1) 69 | 70 | def send_data(self, data): 71 | epdconfig.digital_write(self.dc_pin, 1) 72 | epdconfig.digital_write(self.cs_pin, 0) 73 | epdconfig.spi_writebyte([data]) 74 | epdconfig.digital_write(self.cs_pin, 1) 75 | 76 | def ReadBusy(self): 77 | logging.debug("e-Paper busy") 78 | while(epdconfig.digital_read(self.busy_pin) == 0): 79 | epdconfig.delay_ms(100) 80 | logging.debug("e-Paper busy release") 81 | 82 | def set_lut_bw(self): 83 | self.send_command(0x20) # vcom 84 | for count in range(0, 15): 85 | self.send_data(self.lut_vcom0[count]) 86 | self.send_command(0x21) # ww -- 87 | for count in range(0, 15): 88 | self.send_data(self.lut_w[count]) 89 | self.send_command(0x22) # bw r 90 | for count in range(0, 15): 91 | self.send_data(self.lut_b[count]) 92 | self.send_command(0x23) # wb w 93 | for count in range(0, 15): 94 | self.send_data(self.lut_g1[count]) 95 | self.send_command(0x24) # bb b 96 | for count in range(0, 15): 97 | self.send_data(self.lut_g2[count]) 98 | 99 | def set_lut_red(self): 100 | self.send_command(0x25) 101 | for count in range(0, 15): 102 | self.send_data(self.lut_vcom1[count]) 103 | self.send_command(0x26) 104 | for count in range(0, 15): 105 | self.send_data(self.lut_red0[count]) 106 | self.send_command(0x27) 107 | for count in range(0, 15): 108 | self.send_data(self.lut_red1[count]) 109 | 110 | def init(self): 111 | if (epdconfig.module_init() != 0): 112 | return -1 113 | # EPD hardware init start 114 | self.reset() 115 | 116 | self.send_command(0x01) # POWER_SETTING 117 | self.send_data(0x07) 118 | self.send_data(0x00) 119 | self.send_data(0x08) 120 | self.send_data(0x00) 121 | self.send_command(0x06) # BOOSTER_SOFT_START 122 | self.send_data(0x07) 123 | self.send_data(0x07) 124 | self.send_data(0x07) 125 | self.send_command(0x04) # POWER_ON 126 | 127 | self.ReadBusy() 128 | 129 | self.send_command(0X00) # PANEL_SETTING 130 | self.send_data(0xCF) 131 | self.send_command(0X50) # VCOM_AND_DATA_INTERVAL_SETTING 132 | self.send_data(0x17) 133 | self.send_command(0x30) # PLL_CONTROL 134 | self.send_data(0x39) 135 | self.send_command(0x61) # TCON_RESOLUTION set x and y 136 | self.send_data(0xC8) 137 | self.send_data(0x00) 138 | self.send_data(0xC8) 139 | self.send_command(0x82) # VCM_DC_SETTING_REGISTER 140 | self.send_data(0x0E) 141 | 142 | self.set_lut_bw() 143 | self.set_lut_red() 144 | return 0 145 | 146 | def getbuffer(self, image): 147 | buf = [0xFF] * int(self.width * self.height / 8) 148 | # Set buffer to value of Python Imaging Library image. 149 | # Image must be in mode 1. 150 | image_monocolor = image.convert('1') 151 | imwidth, imheight = image_monocolor.size 152 | if imwidth != self.width or imheight != self.height: 153 | raise ValueError('Image must be same dimensions as display \ 154 | ({0}x{1}).' .format(self.width, self.height)) 155 | 156 | pixels = image_monocolor.load() 157 | for y in range(self.height): 158 | for x in range(self.width): 159 | # Set the bits for the column of pixels at the current position. 160 | if pixels[x, y] == 0: 161 | buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) 162 | return buf 163 | 164 | def display(self, blackimage, redimage): 165 | # send black data 166 | if (blackimage != None): 167 | self.send_command(0x10) # DATA_START_TRANSMISSION_1 168 | for i in range(0, int(self.width * self.height / 8)): 169 | temp = 0x00 170 | for bit in range(0, 4): 171 | if (blackimage[i] & (0x80 >> bit) != 0): 172 | temp |= 0xC0 >> (bit * 2) 173 | self.send_data(temp) 174 | temp = 0x00 175 | for bit in range(4, 8): 176 | if (blackimage[i] & (0x80 >> bit) != 0): 177 | temp |= 0xC0 >> ((bit - 4) * 2) 178 | self.send_data(temp) 179 | 180 | # send red data 181 | if (redimage != None): 182 | self.send_command(0x13) # DATA_START_TRANSMISSION_2 183 | for i in range(0, int(self.width * self.height / 8)): 184 | self.send_data(redimage[i]) 185 | 186 | self.send_command(0x12) # DISPLAY_REFRESH 187 | self.ReadBusy() 188 | 189 | def Clear(self): 190 | self.send_command(0x10) # DATA_START_TRANSMISSION_1 191 | for i in range(0, int(self.width * self.height / 8)): 192 | self.send_data(0xFF) 193 | self.send_data(0xFF) 194 | 195 | self.send_command(0x13) # DATA_START_TRANSMISSION_2 196 | for i in range(0, int(self.width * self.height / 8)): 197 | self.send_data(0xFF) 198 | 199 | self.send_command(0x12) # DISPLAY_REFRESH 200 | self.ReadBusy() 201 | 202 | def sleep(self): 203 | self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING 204 | self.send_data(0x17) 205 | self.send_command(0x82) # to solve Vcom drop 206 | self.send_data(0x00) 207 | self.send_command(0x01) # power setting 208 | self.send_data(0x02) # gate switch to external 209 | self.send_data(0x00) 210 | self.send_data(0x00) 211 | self.send_data(0x00) 212 | self.ReadBusy() 213 | 214 | self.send_command(0x02) # power off 215 | 216 | def Dev_exit(self): 217 | epdconfig.module_exit() 218 | 219 | ### END OF FILE ### 220 | 221 | -------------------------------------------------------------------------------- /lib/waveshare_epd/epd4in01f.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding:utf-8 -*- 3 | # ***************************************************************************** 4 | # * | File : epd4in01f.py 5 | # * | Author : Waveshare team 6 | # * | Function : Electronic paper driver 7 | # * | Info : 8 | # *---------------- 9 | # * | This version: V1.0 10 | # * | Date : 2020-11-06 11 | # # | Info : python demo 12 | # ----------------------------------------------------------------------------- 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documnetation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in 21 | # all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | # THE SOFTWARE. 30 | # 31 | 32 | import logging 33 | from . import epdconfig 34 | 35 | # Display resolution 36 | EPD_WIDTH = 640 37 | EPD_HEIGHT = 400 38 | 39 | class EPD: 40 | def __init__(self): 41 | self.reset_pin = epdconfig.RST_PIN 42 | self.dc_pin = epdconfig.DC_PIN 43 | self.busy_pin = epdconfig.BUSY_PIN 44 | self.cs_pin = epdconfig.CS_PIN 45 | self.width = EPD_WIDTH 46 | self.height = EPD_HEIGHT 47 | self.BLACK = 0x000000 # 0000 BGR 48 | self.WHITE = 0xffffff # 0001 49 | self.GREEN = 0x00ff00 # 0010 50 | self.BLUE = 0xff0000 # 0011 51 | self.RED = 0x0000ff # 0100 52 | self.YELLOW = 0x00ffff # 0101 53 | self.ORANGE = 0x0080ff # 0110 54 | 55 | 56 | # Hardware reset 57 | def reset(self): 58 | epdconfig.digital_write(self.reset_pin, 1) 59 | epdconfig.delay_ms(200) 60 | epdconfig.digital_write(self.reset_pin, 0) 61 | epdconfig.delay_ms(2) 62 | epdconfig.digital_write(self.reset_pin, 1) 63 | epdconfig.delay_ms(200) 64 | 65 | def send_command(self, command): 66 | epdconfig.digital_write(self.dc_pin, 0) 67 | epdconfig.digital_write(self.cs_pin, 0) 68 | epdconfig.spi_writebyte([command]) 69 | epdconfig.digital_write(self.cs_pin, 1) 70 | 71 | def send_data(self, data): 72 | epdconfig.digital_write(self.dc_pin, 1) 73 | epdconfig.digital_write(self.cs_pin, 0) 74 | epdconfig.spi_writebyte([data]) 75 | epdconfig.digital_write(self.cs_pin, 1) 76 | 77 | def ReadBusyHigh(self): 78 | logging.debug("e-Paper busy") 79 | while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy 80 | epdconfig.delay_ms(100) 81 | logging.debug("e-Paper busy release") 82 | 83 | def ReadBusyLow(self): 84 | logging.debug("e-Paper busy") 85 | while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy 86 | epdconfig.delay_ms(100) 87 | logging.debug("e-Paper busy release") 88 | 89 | def init(self): 90 | if (epdconfig.module_init() != 0): 91 | return -1 92 | # EPD hardware init start 93 | self.reset() 94 | 95 | self.ReadBusyHigh() 96 | self.send_command(0x00); 97 | self.send_data(0x2f); 98 | self.send_data(0x00); 99 | self.send_command(0x01); 100 | self.send_data(0x37); 101 | self.send_data(0x00); 102 | self.send_data(0x05); 103 | self.send_data(0x05); 104 | self.send_command(0x03); 105 | self.send_data(0x00); 106 | self.send_command(0x06); 107 | self.send_data(0xC7); 108 | self.send_data(0xC7); 109 | self.send_data(0x1D); 110 | self.send_command(0x41); 111 | self.send_data(0x00); 112 | self.send_command(0x50); 113 | self.send_data(0x37); 114 | self.send_command(0x60); 115 | self.send_data(0x22); 116 | self.send_command(0x61); 117 | self.send_data(0x02); 118 | self.send_data(0x80); 119 | self.send_data(0x01); 120 | self.send_data(0x90); 121 | self.send_command(0xE3); 122 | self.send_data(0xAA); 123 | 124 | # EPD hardware init end 125 | return 0 126 | 127 | def getbuffer(self, image): 128 | buf = [0x00] * int(self.width * self.height / 2) 129 | image_monocolor = image.convert('RGB')#Picture mode conversion 130 | imwidth, imheight = image_monocolor.size 131 | pixels = image_monocolor.load() 132 | logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) 133 | if(imwidth == self.width and imheight == self.height): 134 | for y in range(imheight): 135 | for x in range(imwidth): 136 | # Set the bits for the column of pixels at the current position. 137 | Add = int((x + y * self.width) / 2) 138 | Color = 0; 139 | if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 140 | Color = 0 141 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): 142 | Color = 1 143 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 144 | Color = 2 145 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): 146 | Color = 3 147 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 148 | Color = 4 149 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 150 | Color = 5 151 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): 152 | Color = 6 153 | 154 | data_t = buf[Add]&(~(0xF0 >> ((x % 2)*4))) 155 | buf[Add] = data_t | ((Color << 4) >> ((x % 2)*4)); 156 | 157 | elif(imwidth == self.height and imheight == self.width): 158 | for y in range(imheight): 159 | for x in range(imwidth): 160 | newx = y 161 | newy = self.height - x - 1 162 | Add = int((newx + newy*self.width) / 2) 163 | Color = 0; 164 | if (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 165 | Color = 0 166 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 255): 167 | Color = 1 168 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 169 | Color = 2 170 | elif (pixels[x, y][0] == 0 and pixels[x, y][1] == 0 and pixels[x, y][2] == 255): 171 | Color = 3 172 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 0 and pixels[x, y][2] == 0): 173 | Color = 4 174 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 255 and pixels[x, y][2] == 0): 175 | Color = 5 176 | elif (pixels[x, y][0] == 255 and pixels[x, y][1] == 128 and pixels[x, y][2] == 0): 177 | Color = 6 178 | 179 | data_t = buf[Add]&(~(0xF0 >> ((newx % 2)*4))) 180 | buf[Add] = data_t | ((Color << 4) >> ((newx % 2)*4)); 181 | return buf 182 | 183 | def display(self,image): 184 | self.send_command(0x61)#Set Resolution setting 185 | self.send_data(0x02) 186 | self.send_data(0x80) 187 | self.send_data(0x01) 188 | self.send_data(0x90) 189 | self.send_command(0x10) 190 | for i in range(0, int(EPD_HEIGHT)): 191 | for j in range(0, int(EPD_WIDTH/2)): 192 | self.send_data((image[j+(int(EPD_WIDTH/2)*i)])) 193 | self.send_command(0x04)#0x04 194 | self.ReadBusyHigh() 195 | self.send_command(0x12)#0x12 196 | self.ReadBusyHigh() 197 | self.send_command(0x02) #0x02 198 | self.ReadBusyLow() 199 | epdconfig.delay_ms(500) 200 | 201 | def Clear(self): 202 | self.send_command(0x61)#Set Resolution setting 203 | self.send_data(0x02) 204 | self.send_data(0x80) 205 | self.send_data(0x01) 206 | self.send_data(0x90) 207 | self.send_command(0x10) 208 | for i in range(0, int(EPD_HEIGHT)): 209 | for j in range(0, int(EPD_WIDTH/2)): 210 | self.send_data(0x11) 211 | #BLACK 0x00 /// 0000 212 | #WHITE 0x11 /// 0001 213 | #GREEN 0x22 /// 0010 214 | #BLUE 0x33 /// 0011 215 | #RED 0x44 /// 0100 216 | #YELLOW 0x55 /// 0101 217 | #ORANGE 0x66 /// 0110 218 | #CLEAN 0x77 /// 0111 unavailable Afterimage 219 | self.send_command(0x04)#0x04 220 | self.ReadBusyHigh() 221 | self.send_command(0x12)#0x12 222 | self.ReadBusyHigh() 223 | self.send_command(0x02) #0x02 224 | self.ReadBusyLow() 225 | epdconfig.delay_ms(500) 226 | 227 | def sleep(self): 228 | epdconfig.delay_ms(500) 229 | self.send_command(0x07) # DEEP_SLEEP 230 | self.send_data(0XA5) 231 | 232 | def Dev_exit(self): 233 | epdconfig.module_exit() 234 | --------------------------------------------------------------------------------