Giter VIP home page Giter VIP logo

pico_calendar_display's Introduction

pico_calendar_display

Python project to display Calendar data on a Raspberry Pi Pico W with an e-Paper display

A Companion project to icscalserv (and, in fact, the reason that project was created...).

Resources Required

This is a project using MicroPython on the Pi Pico W. It was built with the following resources:

(note that any recent MicroPython build for PiPico W - certainly anything v1.19.1 or above issued after 20220630, which was when machine.lightsleep() functionality was added- ought to work.)

Installation

  1. Setup your icscalserv instance and take a note of it's data URL
  2. git clone https://github.com/henley-regatta/pico_calendar_display.git to get a local copy of this repository
  3. Wire up ePaper display to Pi Pico W - reference since I had some fun with pinouts etc
  4. Load the MicroPython build onto the PiPico W
  5. Edit main.py to change:
    • ssid to the value of the wireless network to connect to
    • sspass to the WPA wireless password value
    • calendar_url to the URL of the calendar server you'll pull data from
    • refresh_interval_minutes to either the calendar server refresh interval or some multiple thereof
  6. Use Thonny or rshell to copy the python files to the Pico's internal storage
    • Do not rename the existing files or, if you do, be prepared to update the cross-references
  7. Since main.py is automatically called on boot, reset/restart the pico (e.g. machine.reset() in the REPL, or just unplug/replug it...)

Does it work and what does it look like?

Yes. Yes it does. It looks like this: Example of code running on bench showing current calendar data

And if you've got a battery you can even run it on that. Measured power consumption suggests a 500mAh battery should give around a week of runtime thanks to power-saving modes (subject to verification once I leave it alone for a week) Example of PiPico W with ePaper display showing calendar running from LiPo battery using Pimoroni LiPo Pico Shim

Getting Control back of your Pi Pico W

I've found that once machine.lightsleep() has been called, whether it's actually sleeping or not, it's impossible to wrestle back control of the MicroPython environment by getting back to the REPL - Ctrl-F2 (STOP) in Thonny just errors-out. Once this happens it's unplug the Pico and replug it in again.

This is why there's a 10-second LED blinker at the start of the main.py execution; that's enough time (if Thonny is already launched!) to let you STOP and get back to the REPL to make changes if you need to.

Memory Management

As I was ready to push this out and declare "Done" I found it was crashing when booted from scratch. After doing some tracing I found that it was dying out-of-memory when retrieving the calendar. And with some judicious use of gc.mem_free() it became obvious that it's all used in allocating the gpd object that controls the e-Paper. There's some wierdness in that library in that it allocates both a 1-bit-per-pixel array (Image1Gray) and a 2-bit-per-pixel / 4 colour array (Image4Gray), but then never uses the 1-bit ImageBuffer. That's 15K of memory (out of about 150K, 10%) apparently wasted. So I've commented it out; apparently without ill effect but days are early.

This does highlight one of the major limitations of this hardware solution though - memory size is critical. The ability of this particular hardware combination to "scale" - either to larger calendar sizes, or even to larger display sizes (bigger Frame Buffers) is limited. I suspect at some point I'm going to need to ditch the Python environment and start on C development to have greater control over memory consumption.

As a legacy of all this tracing/debugging, there's still a bunch of manual gc.collect() statements strewn around the code base. These are probably unnecessary but at this point I'm not willing to risk it by removing them...

Battery Level Monitoring - Gratitude

I intend to power this with a battery, (using the PiMoroni LiPo SHIM for Pico and a 500mAh LiPo battery) so in preparation I've added code to discover and print battery condition. This uses the example given by Pimoroni here. However, it's important to note that that code only actually works on a Pi Pico.

On a PicoW there are two changes:

  • IP VBUS Sense isn't on GPIO24, it's on WL_GPIO2 (easy!)
  • VSys on GPIO29is shared with Wireless SPI; using it with machine.ADC() will cause the Pico to freeze dead if any network access is attempted

Fortunately, Others have found this before me and in particular a huge shout-out / thanks to user danjperron who came up with a working solution shown in his code here which I have shamelessly stolen borrowed.

Low-power / Sleep modes on the Pi Pico w with an ePaper display attached

Probably the biggest headache in all of this was getting the Pico W to do a low-powered sleep whilst still refreshing the display. The code in main.py was very much arrived at as a trial-and-error way of getting there. An embedded installation would probably want to get rid of the led.toggle() / led.on() calls but I found them useful for debugging, especially as any other sorts of output - like print() - interferes with the sleep processes used.

The Network connect/sleep code probably isn't as robust as it could be but it does appear to work OK in testing over periods of multiple hours. Again, the specific init and (more importantly) de-init code used was found to be necessary in order to get successful low-power sleep via system.lightsleep(). By all accounts the call to wlan.deinit() shouldn't be necessary if wlan.active(False) has been called, but (per discussions) it is. Similarly, the deconstruction of wlan=None is prophylactic against memory leaks given the re-initialisation done at the start of the loop.

The ePaper display's specs warn of all sorts of dire consequences of leaving the display in a hi-power state, and strongly recommend calling epd.Sleep() after every refresh. Except that when a lower-power mode is active, something causes the epaper to dim after a minute or so (the whole screen looks like it's been written in epd.grayish no matter what values were used) if this method alone is used. I found it necessary to augment the call to epd.Sleep() with additional de-initialising calls to epd.reset() and epd.module_exit() at the end of each loop to avoid this. Frankly this is voodoo programming; one of those calls might be enough but since both of them have the desired effect and (so far) seem to avoid memory leaks I've left 'em both in.

In many ways it's a shame system.deepsleep() isn't (yet?) implemented properly on PiPico as that would have a much more beneficial effort from a "code cleanliness" perspective; awakening from deepsleep() is exactly like doing a timed machine.reset() which would clear memory and state and all sorts (one way to eliminate possible memory leaks...). I fear the ePaper may still need it's special handling to avoid damage / fading though.

A note on the WavePaper library

I had to adapt the WavePaper library because as shipped it issues a bunch of print() statements on busy/release. It's a known problem that print interferes with any attempt to do a low-power mode (machine.lightsleep() being used by this project) so I stripped them out.

I'm fairly sure I'm allowed to do this - the licence permits modifications and I've retained the original copyright notice.

The original repository for the examples is at:

You will wish to note that I've used the library that's specific to my actual display - the 4.2" 400x300 board with embedded controller, embodied in the source file Pico-ePaper-4.2py. I believe from a casual inspection that using any of the available demo files as a source should be a fairly simple drop-in replacement as they all follow the same general pattern, although you'll want to change the display code to take advantage e.g. of more colours available.

If I was going to do this myself, I'd use the following approach:

  1. Find the library from the samples provided that matched my display
  2. Copy it to a local version (e.g. "WaveShareEpaper75.py")
  3. Go through that library and comment out all print() statements
  4. Edit the main cal_display.py file in this repository and change references from WaveShareEpaper42 to WaveShareEpaper75

The actual display code in cal_display.py ought to be agnostic to changes in resolution, scaling appropriately, but of course I've had little chance to verify that...

pico_calendar_display's People

Contributors

henley-regatta avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.