Skip to content

Commit

Permalink
Merge pull request #61 from sidoh/v2.6.0
Browse files Browse the repository at this point in the history
v2.6.0
  • Loading branch information
sidoh authored Dec 25, 2020
2 parents 9c94a7d + 7b108c7 commit 24b9724
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 92 deletions.
51 changes: 32 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Template-oriented driver for e-paper displays using Arduino. Define a layout wi
- [Setup](#setup)
- [Requirements](#requirements)
- [Quickstart](#quickstart)
- [Hardware Setup](#hardware-setup)
- [Deep Sleep](#deep-sleep)
- [SPI Bus and Pin Selection](#spi-bus-and-pin-selection)
- [Concepts](#concepts)
- [Variables](#variables)
- [Regions](#regions)
Expand Down Expand Up @@ -59,42 +59,55 @@ The [examples directory](./examples) has a few sample templates. Here are a few

## Quickstart

1. Connect display to MCU. (see [waveshare site](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module) and **SPI Bus and Pin Selection** below for more information)
1. Connect display to MCU. See [Hardware Setup](#hardware-setup) below for more information.
1. Flash your MCU.
1. Use a pre-compiled binary from the [releases page](https://github.com/sidoh/epaper_templates/releases). **Make sure to select the file starting with `INITIALIZER_`**. You can use [esptool](https://github.com/espressif/esptool) or the [ESP32 flash tool](https://www.espressif.com/en/support/download/other-tools). Example command:
```
esptool.py --chip esp32 --baud 460800 write_flash 0x1000 INITIALIZER_epaper_templates_esp32-v2.3.0.bin
```
2. With PlatformIO: for example `pio run -e esp32 -t upload`. You will need to have [nodejs](https://nodejs.org/en/) installed in order to buidl the web assets.
2. Setup WiFi. A setup AP will appear named `epaper_XXXXXX`. The default password is **waveshare**.
3. Visit the Web UI to configure further.
3. Visit the Web UI to configure further. If you used custom pins, make sure to configure those.

## Deep Sleep
## Hardware Setup

e-paper templates can function in _deep sleep_ mode. When configured, the system will continuously:
Waveshare SPI modules have six total data pins that needs to be mapped onto your ESP32. There are **3x SPI pins** and **3x configurable non-SPI pins** you'll need to connect:

1. Wake from sleep
2. Check if a configurable GPIO pin is set. If it is, stays awake until next reboot
3. Otherwise, stay awake for a configurable period to receive updates and refresh the screen.
4. Put both the ESP32 and the e-paper display into deep sleep mode.
|Pin Name|Description|Default pin|
|-|-|-|
|DIN|SPI MOSI|GPIO 13 (HSPI MOSI)|
|CLK|SPI clock|GPIO 14 (HSPI CLK)|
|CS|SPI chip select|GPIO 15 (HSPI SS)
|DC|Data/Command control pin (configurable)|GPIO 17|
|RST|External reset|GPIO 16|
|BUSY|Busy state output pin|GPIO 7|

This is useful if trying to conserve power. Deep sleep mode can be configured in the "Power" tab within the web UI.
If you wish to use different data (non-SPI) pins, those are all configurable in the UI.

## SPI Bus and Pin Selection
#### Custom SPI bus

The ESP32 has 4 SPI busses, however, one is reserved for the chips Flash. (SPI0) and another is often used by PSRAM (SP1).
The ESP32 has two available SPI busses. The default is HSPI, but you can select VSPI in the settings page. Some driver boards like the [Waveshare ESP32 Driver](https://www.waveshare.com/wiki/E-Paper_ESP32_Driver_Board) use custom SPI pins.

In the **Hardware** tab of the settings page, you can select one of the two free SPI busses on the ESP32. (HSPI and VSPI)

| | VSPI | HSPI (default) |
|-----------|------|----------------|
| DI (MOSI) | 19 | 12 |
| CLK | 18 | 14 |
| CS (SS) | 5 | 15 |
| | VSPI | HSPI (default) | Waveshare Custom |
|-----------|------|----------------|-|
| DI (MOSI) | 19 | 12 |14|
| CLK | 18 | 14 |13|
| CS (SS) | 5 | 15 |15|

Additionally, the displays will require extra pins to be configured to work properly. These are also selectable in the **Hardware** tab.
Ensure that you do not select pins that conflict with the your SPI Bus/Deep Sleep configurations.

## Deep Sleep

Please ensure that you do not select pins that conflict with the your SPI Bus/Deep Sleep configurations.
e-paper templates can function in _deep sleep_ mode. When configured, the system will continuously:

1. Wake from sleep
2. Check if a configurable GPIO pin is set. If it is, stays awake until next reboot
3. Otherwise, stay awake for a configurable period to receive updates and refresh the screen.
4. Put both the ESP32 and the e-paper display into deep sleep mode.

This is useful if trying to conserve power. Deep sleep mode can be configured in the "Power" tab within the web UI.

# Concepts

Expand Down
11 changes: 11 additions & 0 deletions lib/Display/DisplayTemplateDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ DisplayTemplateDriver::DisplayTemplateDriver(
void DisplayTemplateDriver::init() {
display->init(115200);
display->mirror(false);

#if defined(ESP32)
if (settings.hardware.spi_bus == VSPI){
SPI.end();
SPI.begin(18, 23, 19, settings.hardware.getSsPin());
} else if (settings.hardware.spi_bus == HardwareSettings::WAVESHARE_SPI) {
SPI.end();
SPI.begin(13, 12, 14, settings.hardware.getSsPin());
}
#endif

vars.load();
}

Expand Down
58 changes: 29 additions & 29 deletions lib/Display/DisplayTypeHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
#include <utility>

template <class Display>
inline static GxEPD2_GFX* __gxepd2_build_bw_driver(const uint8_t dc, const uint8_t rst, const uint8_t busy) {
return new GxEPD2_BW<Display, Display::HEIGHT>(Display(SS, dc, rst, busy));
inline static GxEPD2_GFX* __gxepd2_build_bw_driver(const uint8_t dc, const uint8_t rst, const uint8_t busy, const uint8_t ssPin) {
return new GxEPD2_BW<Display, Display::HEIGHT>(Display(ssPin, dc, rst, busy));
}

template <class Display>
inline static GxEPD2_GFX* __gxepd2_build_3c_driver(const uint8_t dc, const uint8_t rst, const uint8_t busy) {
return new GxEPD2_3C<Display, Display::HEIGHT>(Display(SS, dc, rst, busy));
inline static GxEPD2_GFX* __gxepd2_build_3c_driver(const uint8_t dc, const uint8_t rst, const uint8_t busy, const uint8_t ssPin) {
return new GxEPD2_3C<Display, Display::HEIGHT>(Display(ssPin, dc, rst, busy));
}

const std::map<const char*, GxEPD2::Panel, cmp_str> DisplayTypeHelpers::PANELS_BY_NAME = {
Expand Down Expand Up @@ -162,59 +162,59 @@ bool DisplayTypeHelpers::is3Color(GxEPD2::Panel type) {
}
}

GxEPD2_GFX* DisplayTypeHelpers::buildDisplay(GxEPD2::Panel type, uint8_t dc, uint8_t rst, uint8_t busy) {
GxEPD2_GFX* DisplayTypeHelpers::buildDisplay(GxEPD2::Panel type, uint8_t dc, uint8_t rst, uint8_t busy, uint8_t ss) {
switch (type) {
// black/white displays
case GxEPD2::Panel::GDEP015OC1:
return __gxepd2_build_bw_driver<GxEPD2_154>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_154>(dc, rst, busy, ss);
case GxEPD2::Panel::GDE0213B1:
return __gxepd2_build_bw_driver<GxEPD2_213>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_213>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEH0213B72:
return __gxepd2_build_bw_driver<GxEPD2_213_B72>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_213_B72>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0213I5F:
return __gxepd2_build_bw_driver<GxEPD2_213_flex>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_213_flex>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEH029A1:
return __gxepd2_build_bw_driver<GxEPD2_290>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_290>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW029T5:
return __gxepd2_build_bw_driver<GxEPD2_290_T5>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_290_T5>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW027W3:
return __gxepd2_build_bw_driver<GxEPD2_270>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_270>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW042T2:
return __gxepd2_build_bw_driver<GxEPD2_420>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_420>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0583T7:
return __gxepd2_build_bw_driver<GxEPD2_583>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_583>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW075T8:
return __gxepd2_build_bw_driver<GxEPD2_750>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_750>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEH0213B73:
return __gxepd2_build_bw_driver<GxEPD2_213_B73>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_213_B73>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW026T0:
return __gxepd2_build_bw_driver<GxEPD2_260>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_260>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0371W7:
return __gxepd2_build_bw_driver<GxEPD2_371>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_371>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW075T7:
return __gxepd2_build_bw_driver<GxEPD2_750_T7>(dc, rst, busy);
return __gxepd2_build_bw_driver<GxEPD2_750_T7>(dc, rst, busy, ss);

// Color displays
case GxEPD2::Panel::ED060SCT:
return __gxepd2_build_3c_driver<GxEPD2_it60>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_it60>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0154Z04:
return __gxepd2_build_3c_driver<GxEPD2_154c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_154c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0213Z16:
return __gxepd2_build_3c_driver<GxEPD2_213c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_213c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW029Z10:
return __gxepd2_build_3c_driver<GxEPD2_290c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_290c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW027C44:
return __gxepd2_build_3c_driver<GxEPD2_270c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_270c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW042Z15:
return __gxepd2_build_3c_driver<GxEPD2_420c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_420c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW0583Z21:
return __gxepd2_build_3c_driver<GxEPD2_583c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_583c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW075Z09:
return __gxepd2_build_3c_driver<GxEPD2_750c>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_750c>(dc, rst, busy, ss);
case GxEPD2::Panel::GDEW075Z08:
return __gxepd2_build_3c_driver<GxEPD2_750c_Z08>(dc, rst, busy);
return __gxepd2_build_3c_driver<GxEPD2_750c_Z08>(dc, rst, busy, ss);
default:
Serial.printf_P(PSTR("Unsupported display type, using default. Provided display: %d\n"), static_cast<size_t>(type));
return buildDisplay(DisplayTypeHelpers::DEFAULT_PANEL, dc, rst, busy);
return buildDisplay(DisplayTypeHelpers::DEFAULT_PANEL, dc, rst, busy, ss);
}
}
2 changes: 1 addition & 1 deletion lib/Display/DisplayTypeHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DisplayTypeHelpers {
static GxEPD2::Panel stringToDisplayType(const String& displayType);
static bool is3Color(GxEPD2::Panel type);

static GxEPD2_GFX* buildDisplay(GxEPD2::Panel type, uint8_t dcPin, uint8_t rstPin, uint8_t busyPin);
static GxEPD2_GFX* buildDisplay(GxEPD2::Panel type, uint8_t dcPin, uint8_t rstPin, uint8_t busyPin, uint8_t ssPin);

static const GxEPD2::Panel DEFAULT_PANEL;
static const char* DISPLAY_NAMES[];
Expand Down
15 changes: 15 additions & 0 deletions lib/Settings/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,19 @@ void SettingsCallbackObserver::onConfigurationChanged(const ConfigurationPropert
if (this->callback) {
this->callback(value);
}
}

const uint8_t HardwareSettings::getSsPin() const {
if (this->ss_pin_override != -1) {
return static_cast<uint8_t>(this->ss_pin_override);
}

switch (this->spi_bus) {
case HSPI:
case WAVESHARE_SPI:
return 15;
case VSPI:
default:
return 5;
}
}
11 changes: 11 additions & 0 deletions lib/Settings/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,27 @@ class WebSettings : public Configuration {

class HardwareSettings : public Configuration {
public:
static const uint8_t WAVESHARE_SPI = VSPI + HSPI;
static const uint8_t WAVESHARE_SS_PIN = 15;

persistentVar(
uint8_t,
spi_bus,
EPD_DEFAULT_SPI_BUS,
{
if (spi_busString.equalsIgnoreCase("vspi")) {
spi_bus = VSPI;
} else if (spi_busString.equalsIgnoreCase("waveshare")) {
spi_bus = WAVESHARE_SPI;
} else {
spi_bus = HSPI;
}
},
{
if (spi_bus == VSPI) {
spi_busString = "VSPI";
} else if (spi_bus == WAVESHARE_SPI) {
spi_busString = "waveshare";
} else {
spi_busString = "HSPI";
}
Expand All @@ -101,12 +108,16 @@ class HardwareSettings : public Configuration {
persistentIntVar(dc_pin, EPD_DEFAULT_DC_PIN);
persistentIntVar(rst_pin, EPD_DEFAULT_RST_PIN);
persistentIntVar(busy_pin, EPD_DEFAULT_BUSY_PIN);
persistentIntVar(ss_pin_override, -1);

const uint8_t getSsPin() const;
};

class NetworkSettings : public Configuration {
public:
persistentStringVar(hostname, DEFAULT_DISPLAY_NAME);
persistentStringVar(mdns_name, DEFAULT_DISPLAY_NAME);
persistentStringVar(ntp_server, "pool.ntp.org");
persistentStringVar(setup_ap_password, "waveshare");
persistentStringVar(wifi_ssid, "");
persistentStringVar(wifi_password, "");
Expand Down
1 change: 1 addition & 0 deletions lib/Variables/VariableDictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ String VariableDictionary::get(const String &key) {
}

void VariableDictionary::clear() {
SPIFFS.remove(VariableDictionary::FILENAME);
SPIFFS.open(VariableDictionary::FILENAME, "w").close();

db.open(SPIFFS.open(VariableDictionary::FILENAME, "r+"));
Expand Down
4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ framework = arduino
board_f_cpu = 80000000L
lib_deps_builtin =
lib_deps_external =
ArduinoJson@~6.10.1
ArduinoJson@~6.17.1
Adafruit GFX Library@~1.6.1
Timezone@~1.2.2
AsyncMqttClient@~0.8.2
Expand All @@ -31,7 +31,7 @@ lib_deps_external =
; and the webserver builtin to the espressif SDKs define.
WiFiManager=https://github.com/sidoh/WiFiManager#async_support

GxEPD2=https://github.com/ZinggJM/GxEPD2#1.2.3
GxEPD2=https://github.com/ZinggJM/GxEPD2#1.2.14
extra_scripts =
pre:scripts/platformio/build_web.py
post:scripts/platformio/build_full_image.py
Expand Down
26 changes: 13 additions & 13 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ GxEPD2_GFX* display = NULL;
DisplayTemplateDriver* driver = NULL;
EpaperWebServer* webServer = NULL;
MqttClient* mqttClient = NULL;
NTPClient* timeClient;

// Don't attempt to reconnect to wifi if we've never connected
volatile bool hasConnected = false;
volatile bool shouldRestart = false;

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000);

uint8_t lastSecond = 60;

Expand Down Expand Up @@ -73,13 +73,6 @@ void cancelSleep() {
}

void initDisplay() {
#if defined(ESP32)
if (settings.hardware.spi_bus == VSPI){
SPI.end();
SPI.begin(18, 23, 19, 5);
}
#endif

if (display) {
delete display;
display = NULL;
Expand All @@ -88,7 +81,8 @@ void initDisplay() {
display = DisplayTypeHelpers::buildDisplay(settings.display.display_type,
settings.hardware.dc_pin,
settings.hardware.rst_pin,
settings.hardware.busy_pin);
settings.hardware.busy_pin,
settings.hardware.getSsPin());

if (driver != NULL) {
delete driver;
Expand All @@ -115,6 +109,14 @@ void applySettings() {

Timezones.setDefaultTimezone(*settings.system.timezone);

if (timeClient != NULL) {
delete timeClient;
timeClient = NULL;
}

timeClient = new NTPClient(ntpUDP, settings.network.ntp_server.c_str(), 0, 60000);
timeClient->begin();

if (hasConnected && settings.network.wifi_ssid.length() > 0 &&
settings.network.wifi_ssid != WiFi.SSID()) {
Serial.println(F("Switching WiFi networks"));
Expand Down Expand Up @@ -255,8 +257,6 @@ void setup() {
}
}

timeClient.begin();

applySettings();
}

Expand All @@ -265,9 +265,9 @@ void loop() {
ESP.restart();
}

if (timeClient.update() && lastSecond != second()) {
if (timeClient != NULL && timeClient->update() && lastSecond != second()) {
lastSecond = second();
driver->updateVariable("timestamp", String(timeClient.getEpochTime()));
driver->updateVariable("timestamp", String(timeClient->getEpochTime()));
}

if (webServer) {
Expand Down
Loading

0 comments on commit 24b9724

Please sign in to comment.