Skip to content

A modular Node.js driver for Waveshare E-Paper displays that supports multiple display models with different resolutions and color modes

License

Notifications You must be signed in to change notification settings

anders94/waveshare-epaper

Repository files navigation

Waveshare E-Paper Node.js Driver

npm version

A modular Node.js driver for Waveshare E-Paper displays that supports multiple display models with different resolutions and color modes.

Features

  • Modular architecture: Easy to extend with new display models
  • Multiple display support: Currently supports 8+ display models with more easily added
  • Color mode support: Monochrome, grayscale and color modes where supported by hardware
  • Common API: Unified interface across all display models
  • Hardware abstraction: Base class handles common SPI/GPIO operations
  • PNG image loading: Built-in support for loading and displaying PNG images

Supported Displays

Not all devices have been tested in the field. Please create a GitHub issue if you have confirmed one of the untested platforms working.

Model Resolution Color Modes Description Status
2in13 122 × 250 Monochrome 2.13" black/white Untested
2in7 176 × 264 Mono, 4-grayscale 2.7" with grayscale support Untested
2in7b 176 × 264 3-color 2.7" black/white/red or yellow Untested
7in5 640 × 384 Monochrome 7.5" black/white Confirmed working
7in3f 800 × 480 7-color 7.3" full color (7 colors) Untested
13in3k 960 × 680 Mono, 4-grayscale 13.3" with grayscale support Confirmed working
13in3b 960 × 680 3-color 13.3" black/white/red or yellow Untested
13in3gray 1600 × 1200 16-grayscale 13.3" 16-level grayscale (IT8951) Untested

Installation

npm install waveshare-epaper

GPIO Permissions (Recommended)

For security, add your user to the gpio group instead of running as root:

# Add current user to gpio group
sudo usermod -a -G gpio $USER

# Log out and back in, then verify group membership
groups

After logging back in, you can run GPIO programs without sudo.

Quick Start

13.3" 4-grayscale Example

const { createDisplay } = require('waveshare-epaper');

(async () => {
    // Create display instance (13.3" 4-grayscale)
    const epd = createDisplay('13in3k', '4gray', {
        rstPin: 17,
        dcPin: 25,
        busyPin: 24,
        pwrPin: 18
    });

    // Initialize and use
    await epd.init();
    await epd.clear();

    // Draw with different gray levels (0=black, 1=dark gray, 2=light gray, 3=white)
    epd.drawRect(10, 10, 100, 50, 0, true);   // Black filled rectangle
    epd.drawRect(120, 10, 100, 50, 1, true);  // Dark gray rectangle
    epd.drawRect(230, 10, 100, 50, 2, true);  // Light gray rectangle
    epd.drawLine(10, 80, 330, 80, 0);         // Black line

    // Update display
    await epd.display();
    await epd.sleep();
})();

16-grayscale Example (IT8951 Controller)

const { createDisplay } = require('waveshare-epaper');

(async () => {
    const epd = createDisplay('13in3gray', '16gray', {
        rstPin: 17,
        dcPin: 25,
        busyPin: 24,
        pwrPin: 18,
        vcom: -2.30  // Adjust according to your display
    });

    await epd.init();
    await epd.clear();

    // Draw with 16 different gray levels (0=black, 15=white)
    const cellWidth = 100;
    for (let i = 0; i < 16; i++) {
        const x = (i % 8) * cellWidth;
        const y = Math.floor(i / 8) * 60;
        epd.drawRect(x, y, cellWidth - 2, 58, i, true);
    }

    // Display with high quality GC16 mode
    await epd.display('GC16');
    await epd.sleep();
})();

Canvas Example

Requires: npm install canvas

const { createDisplay } = require('waveshare-epaper');

(async () => {
    const { createCanvas } = require('canvas');
    const epd = createDisplay('13in3k', '4gray', {
        rstPin: 17, dcPin: 25, busyPin: 24, pwrPin: 18
    });

    await epd.init();

    // Create a simple canvas
    const canvas = createCanvas(400, 200);
    const ctx = canvas.getContext('2d');

    // White background
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Draw text and shapes
    ctx.fillStyle = 'black';
    ctx.font = '36px Arial';
    ctx.fillText('Canvas Demo', 50, 100);

    // Draw a rectangle around the text
    ctx.strokeStyle = 'gray';
    ctx.lineWidth = 2;
    ctx.strokeRect(10, 10, 380, 180);

    // Draw to display
    await epd.drawCanvas(canvas, 100, 100);
    await epd.display();
    await epd.sleep();
})();

API Reference

Factory Functions

createDisplay(model, colorMode, options)

Creates a display instance for the specified model.

  • model (string): Display model ('2in13', '2in7', '2in7b', '7in5', '7in3f', '13in3k', '13in3b', '13in3gray')
  • colorMode (string): Color mode ('mono', '4gray', '16gray', '3color', '7color') - must be supported by the display
  • options (object): Configuration options

Options:

  • rstPin (number): Reset GPIO pin (default: 17)
  • dcPin (number): Data/Command GPIO pin (default: 25)
  • busyPin (number): Busy GPIO pin (default: 24)
  • csPin (number): Chip Select GPIO pin (default: 22)
  • pwrPin (number): Power control GPIO pin (default: 18)
  • gpioChip (string): GPIO chip name (default: 'gpiochip0')
  • busNumber (number): SPI bus number (default: 0)
  • deviceNumber (number): SPI device number (default: 0)
  • maxSpeedHz (number): SPI max speed (default: 4000000)
  • accentColor (string): For 3-color displays, specify 'red' or 'yellow' accent color
  • vcom (number): VCOM voltage for IT8951 displays (default: -2.30)

getSupportedModels()

Returns array of supported models with their specifications.

Display Methods

Basic Operations

  • await epd.init() - Initialize the display
  • await epd.clear() - Clear display to background color
  • await epd.display() - Update the display with current buffer
  • await epd.sleep() - Put display into low power mode
  • await epd.cleanup() - Clean up resources

Power Control

  • await epd.powerOn() - Turn on display power (automatically called during init)
  • await epd.powerOff() - Turn off display power (automatically called during cleanup)

Drawing Functions

  • epd.setPixel(x, y, color) - Set individual pixel
  • epd.drawLine(x0, y0, x1, y1, color) - Draw line
  • epd.drawRect(x, y, width, height, color, filled) - Draw rectangle
  • await epd.drawPNG(filePath, x, y) - Load and draw PNG image
  • await epd.drawCanvas(canvas, x, y) - Draw HTML5 Canvas object

Enhanced Drawing (Color Displays)

7-color displays:

  • epd.setPixelColor(x, y, colorName) - Set pixel using color name
  • epd.drawColorLine(x0, y0, x1, y1, colorName) - Draw colored line
  • epd.drawColorRect(x, y, w, h, colorName, filled) - Draw colored rectangle
  • await epd.show7Block() - Display all 7 colors in blocks

3-color displays:

  • epd.drawBlackRect(x, y, w, h, filled) - Draw black rectangle
  • epd.drawRedRect(x, y, w, h, filled) - Draw accent color rectangle
  • await epd.show3ColorTest() - Display 3-color test pattern

Color Values

  • Monochrome mode: 0 = black, 1 = white
  • 4-grayscale mode: 0 = black, 1 = dark gray, 2 = light gray, 3 = white
  • 16-grayscale mode: 0 = black, 1-14 = varying gray levels, 15 = white
  • 3-color mode: 0 = black, 1 = white, 2 = accent color (red or yellow, configurable)
  • 7-color mode: 0 = black, 1 = white, 2 = green, 3 = blue, 4 = red, 5 = yellow, 6 = orange

Color Names (7-color displays)

For 7-color displays, you can use color names:

epd.setPixelColor(x, y, 'RED');
epd.drawColorRect(10, 10, 100, 50, 'BLUE', true);
epd.drawColorLine(0, 0, 100, 100, 'GREEN');

Available colors: BLACK, WHITE, RED, GREEN, BLUE, YELLOW, ORANGE

Architecture

File Structure

├── index.js              # Main entry point and factory functions
├── EPDBase.js             # Base class with common functionality
├── displays/
│   ├── index.js           # Display module exports
│   ├── EPD2in13.js        # 2.13" monochrome display driver
│   ├── EPD2in7.js         # 2.7" mono/4-grayscale display driver
│   ├── EPD2in7b.js        # 2.7" 3-color display driver
│   ├── EPD7in5.js         # 7.5" monochrome display driver
│   ├── EPD7in3f.js        # 7.3" 7-color display driver
│   ├── EPD13in3k.js       # 13.3" mono/4-grayscale display driver
│   ├── EPD13in3b.js       # 13.3" 3-color display driver
│   └── EPD13in3Gray.js    # 13.3" 16-grayscale display driver (IT8951)
├── examples/              # Usage examples for each feature
└── README.md              # This file

Extending with New Displays

To add support for a new display model:

  1. Create a new file in displays/ (e.g., EPDNewModel.js)

  2. Extend EPDBase class:

    const EPDBase = require('../EPDBase');
    
    class EPDNewModel extends EPDBase {
        constructor(options = {}) {
            super(options);
            this.width = 200;    // Set display width
            this.height = 200;   // Set display height
            this.colorMode = options.colorMode || 'mono';
            this.bitsPerPixel = this.colorMode === '4gray' ? 2 : 1;
            this.initializeBuffer();
        }
    
        async initDisplay() {
            // Implement display-specific initialization
        }
    
        async displayImage() {
            // Implement display-specific image update
        }
    }
  3. Add to displays/index.js exports

  4. Add case to createDisplay() function

Hardware Requirements

System Requirements

  • Raspberry Pi with SPI enabled
  • gpiod tools installed (apt install gpiod)
  • Node.js 14+ (recommended: Node.js 18+)

Raspberry Pi Model Compatibility

Model GPIO Chip Pin Layout SPI Interface Initialization Notes
Pi 1 Model A/B gpiochip0 26-pin (original) /dev/spidev0.0 Limited pins, use adapted wiring
Pi 1 Model A+/B+ gpiochip0 40-pin /dev/spidev0.0 Full compatibility
Pi 2 Model B gpiochip0 40-pin /dev/spidev0.0 Full compatibility
Pi 3 Model A+/B+ gpiochip0 40-pin /dev/spidev0.0 Full compatibility
Pi 4 Model B gpiochip0 40-pin /dev/spidev0.0 Full compatibility
Pi 5 gpiochip4 40-pin /dev/spidev0.0 Requires gpioChip option

Raspberry Pi 5 Configuration

Critical: Pi 5 uses gpiochip4 instead of gpiochip0. You must specify this in your configuration or initialization will fail:

const epd = createDisplay('13in3k', 'mono', {
    rstPin: 17,
    dcPin: 25,
    busyPin: 24,
    pwrPin: 18,
    gpioChip: 'gpiochip4'  // Required for Pi 5
});

Legacy Pi Models (26-pin)

Original Pi 1 Model A/B have only 26 GPIO pins. Use this pin mapping:

  • RST: GPIO 17 ✓ (available)
  • DC: GPIO 25 ✓ (available)
  • CS: GPIO 22 ✓ (available)
  • BUSY: GPIO 24 ✓ (available)
  • PWR: GPIO 18 ✓ (available)

GPIO Pin Connections

The following GPIO pins are required for proper operation:

Function Default Pin Description
RST GPIO 17 Reset signal (output)
DC GPIO 25 Data/Command signal (output)
CS GPIO 22 SPI Chip Select (output)
BUSY GPIO 24 Busy status signal (input)
PWR GPIO 18 Power control (output) - Critical for cold boot operation

Important: The power pin (PWR) is essential for reliable operation, especially when cold-booting the Raspberry Pi. Many Waveshare e-paper displays require explicit power control to function properly. Without this pin, the display may:

  • Not respond to commands after a cold boot
  • Work only after running other display programs first
  • Show inconsistent initialization behavior

SPI Configuration

The driver uses SPI interface with these default settings:

  • SPI Bus: /dev/spidev0.0 (bus 0, device 0)
  • Speed: 4 MHz (configurable)
  • Mode: SPI Mode 0 (CPOL=0, CPHA=0)

Enable SPI on Raspberry Pi

sudo raspi-config
# Navigate to: Interfacing Options → SPI → Enable
# Or add to /boot/config.txt:
echo "dtparam=spi=on" | sudo tee -a /boot/config.txt
sudo reboot

Troubleshooting

Display Not Working After Cold Boot

Symptoms: Display appears to initialize (no errors) but screen doesn't update, or works only after running manufacturer's example programs.

Cause: Missing power pin configuration. Many Waveshare displays have internal power management that requires explicit control.

Solution: Always specify the power pin in your configuration:

const epd = createDisplay('13in3k', 'mono', {
    rstPin: 17,
    dcPin: 25,
    busyPin: 24,
    pwrPin: 18
});

Common GPIO Issues

Permission errors: Make sure you're running with appropriate permissions or add your user to the gpio group:

sudo usermod -a -G gpio $USER
# Then log out and back in

GPIO already in use: If you see "Device or resource busy" errors, check what's using the GPIO pins:

# Check what's using GPIO pins
sudo lsof /dev/gpiomem
# Or check specific pins
gpioinfo | grep -E "(17|18|24|25)"

Auto-Detection and Troubleshooting

Checking Your GPIO Chip

If you're unsure which GPIO chip your Pi uses, run:

gpioinfo | head -n 1

For Pi 5, you'll see: gpiochip4 - 54 lines For older Pi models: gpiochip0 - 54 lines (or similar)

Environment Variable (Alternative)

You can also set the GPIO chip via environment variable:

export GPIO_CHIP=gpiochip4  # For Pi 5
node your-epd-program.js

Then check for this variable in your code:

const epd = createDisplay('13in3k', 'mono', {
    gpioChip: process.env.GPIO_CHIP || 'gpiochip0'
});

Cairo Error

If while loading canvas you get this error:

Error: libcairo.so.2: ELF load command address/offset not page-aligned

Tru removing canvas and re-installing by compiling from source.

rm -fr node_modules/canvas/
npm install canvas --build-from-source

This can happen if you compile Node.js from source because the precompiled ciaro library that comes with canvas might not be compatible with what you have.

Examples

See the examples/ directory for working examples of each feature. Each example demonstrates a specific capability and can be copied directly into your projects.

Usage Examples

7-Color Display Example

const epd = createDisplay('7in3f', '7color');
await epd.init();

// Show all 7 colors in blocks
await epd.show7Block();

// Draw using color names
epd.drawColorRect(50, 50, 100, 80, 'RED', true);
epd.drawColorLine(0, 100, 800, 100, 'BLUE');
epd.setPixelColor(10, 10, 'GREEN');

await epd.display();

3-Color Display Example

// Black/White/Red display
const epd = createDisplay('13in3b', 'red');
// Or Black/White/Yellow display
const epd = createDisplay('13in3b', 'yellow');

await epd.init();

// Draw in different colors
epd.drawBlackRect(50, 50, 200, 100, true);  // Black rectangle
epd.drawRedRect(300, 50, 200, 100, true);   // Accent color rectangle
// White is the background color

// Show test pattern
await epd.show3ColorTest();

Canvas Support

The drawCanvas() method allows rendering HTML5 Canvas objects directly to the display. This enables dynamic text rendering with TrueType fonts, graphics drawing, and complex layouts:

const { createCanvas, registerFont } = require('canvas');

// Register a TrueType font
registerFont('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', { family: 'MyFont' });

// Create and configure canvas
const canvas = createCanvas(800, 400);
const ctx = canvas.getContext('2d');

// White background
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Draw text with custom font
ctx.fillStyle = 'black';
ctx.font = '48px MyFont';
ctx.textAlign = 'center';
ctx.fillText('Hello E-Paper!', canvas.width / 2, canvas.height / 2);

// Draw graphics
ctx.strokeStyle = 'black';
ctx.lineWidth = 3;
ctx.strokeRect(10, 10, canvas.width - 20, canvas.height - 20);

// Render to display
await epd.drawCanvas(canvas, 0, 0);

Canvas Features:

  • TrueType font rendering with canvas package
  • Text, shapes, gradients, and complex graphics
  • Automatic color conversion for all display modes
  • Transparency support (transparent pixels become background color)
  • Full HTML5 Canvas API compatibility

Requirements: Install the canvas package for Canvas support:

npm install canvas

See canvas-example.js for a complete working example.

Advanced Color Detection

The driver automatically converts PNG images to the appropriate color format:

// 7-color display will convert RGB to nearest of 7 colors
await epd.drawPNG('colorful-image.png', 0, 0);

// 3-color display will detect red/yellow regions and convert others to black/white
await epd.drawPNG('mixed-color-image.png', 0, 0);

Migration from Original Code

The original display classes are still available for backward compatibility:

const { EPD13in3k } = require('waveshare-epaper');
const epd = new EPD13in3k();

However, using the new factory function is recommended:

const { createDisplay } = require('waveshare-epaper');
const epd = createDisplay('13in3k', 'mono');

Publishing

To publish a new version to npm:

npm version patch  # or minor/major
npm publish

License

MIT License - see LICENSE file for details.

Based on Waveshare example code.

About

A modular Node.js driver for Waveshare E-Paper displays that supports multiple display models with different resolutions and color modes

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published