feat: Add OLED size build flag support and implement PowerManager for enhanced power management
This commit is contained in:
16
README.md
16
README.md
@@ -15,3 +15,19 @@ ESP32 + SH1106 OLED + soil moisture buddy with expressions.
|
|||||||
## Wiring
|
## Wiring
|
||||||
- OLED (I2C): SDA=GPIO21, SCL=GPIO22, VCC=3.3V, GND=GND
|
- OLED (I2C): SDA=GPIO21, SCL=GPIO22, VCC=3.3V, GND=GND
|
||||||
- Moisture sensor analog out: GPIO34
|
- Moisture sensor analog out: GPIO34
|
||||||
|
|
||||||
|
## OLED Size Build Flag
|
||||||
|
FacePlant now supports compile-time OLED profiles via `PB_OLED_SIZE`:
|
||||||
|
- `96` for 0.96" OLED
|
||||||
|
- `130` for 1.3" OLED
|
||||||
|
- `240` for 2.4" OLED
|
||||||
|
|
||||||
|
Predefined PlatformIO environments:
|
||||||
|
- `esp32-s3-oled-096`
|
||||||
|
- `esp32-s3-oled-130`
|
||||||
|
- `esp32-s3-oled-240`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
pio run -e esp32-s3-oled-240 -t upload
|
||||||
|
```
|
||||||
|
|||||||
@@ -25,3 +25,73 @@ build_flags =
|
|||||||
-D PB_VERSION=\"1.0.0\"
|
-D PB_VERSION=\"1.0.0\"
|
||||||
-D PB_HOSTNAME=\"faceplant\"
|
-D PB_HOSTNAME=\"faceplant\"
|
||||||
-D PB_TZ=\"America/New_York\"
|
-D PB_TZ=\"America/New_York\"
|
||||||
|
-D PB_OLED_SIZE=130
|
||||||
|
|
||||||
|
[env:esp32-s3-oled-096]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_deps =
|
||||||
|
adafruit/Adafruit GFX Library
|
||||||
|
adafruit/Adafruit SH110X
|
||||||
|
adafruit/Adafruit VEML7700 Library
|
||||||
|
adafruit/Adafruit MPU6050
|
||||||
|
adafruit/Adafruit MAX1704X
|
||||||
|
bblanchon/ArduinoJson
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
|
build_flags =
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D PB_VERSION=\"1.0.0\"
|
||||||
|
-D PB_HOSTNAME=\"faceplant\"
|
||||||
|
-D PB_TZ=\"America/New_York\"
|
||||||
|
-D PB_OLED_SIZE=96
|
||||||
|
|
||||||
|
[env:esp32-s3-oled-130]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_deps =
|
||||||
|
adafruit/Adafruit GFX Library
|
||||||
|
adafruit/Adafruit SH110X
|
||||||
|
adafruit/Adafruit VEML7700 Library
|
||||||
|
adafruit/Adafruit MPU6050
|
||||||
|
adafruit/Adafruit MAX1704X
|
||||||
|
bblanchon/ArduinoJson
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
|
build_flags =
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D PB_VERSION=\"1.0.0\"
|
||||||
|
-D PB_HOSTNAME=\"faceplant\"
|
||||||
|
-D PB_TZ=\"America/New_York\"
|
||||||
|
-D PB_OLED_SIZE=130
|
||||||
|
|
||||||
|
[env:esp32-s3-oled-240]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
framework = arduino
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_deps =
|
||||||
|
adafruit/Adafruit GFX Library
|
||||||
|
adafruit/Adafruit SH110X
|
||||||
|
adafruit/Adafruit VEML7700 Library
|
||||||
|
adafruit/Adafruit MPU6050
|
||||||
|
adafruit/Adafruit MAX1704X
|
||||||
|
bblanchon/ArduinoJson
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
|
build_flags =
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D PB_VERSION=\"1.0.0\"
|
||||||
|
-D PB_HOSTNAME=\"faceplant\"
|
||||||
|
-D PB_TZ=\"America/New_York\"
|
||||||
|
-D PB_OLED_SIZE=240
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "../net/WebhookService.h"
|
#include "../net/WebhookService.h"
|
||||||
|
|
||||||
#include "../ui/Display.h"
|
#include "../ui/Display.h"
|
||||||
|
#include "../power/PowerManager.h"
|
||||||
#include "../sensors/MoistureSensor.h"
|
#include "../sensors/MoistureSensor.h"
|
||||||
#include "../sensors/BatterySensor.h"
|
#include "../sensors/BatterySensor.h"
|
||||||
#include "../sensors/AmbientLightSensor.h"
|
#include "../sensors/AmbientLightSensor.h"
|
||||||
@@ -29,6 +30,7 @@ static BatterySensor battery;
|
|||||||
static AmbientLightSensor ambient;
|
static AmbientLightSensor ambient;
|
||||||
static MotionSensor motion;
|
static MotionSensor motion;
|
||||||
static FaceRenderer face;
|
static FaceRenderer face;
|
||||||
|
static PowerManager power;
|
||||||
|
|
||||||
static unsigned long bootMs = 0;
|
static unsigned long bootMs = 0;
|
||||||
|
|
||||||
@@ -48,6 +50,9 @@ static bool restartButtonStable = true;
|
|||||||
static unsigned long restartButtonLastEdgeMs = 0;
|
static unsigned long restartButtonLastEdgeMs = 0;
|
||||||
static unsigned long restartButtonPressedSinceMs = 0;
|
static unsigned long restartButtonPressedSinceMs = 0;
|
||||||
static bool restartButtonArmed = true;
|
static bool restartButtonArmed = true;
|
||||||
|
static bool networkServicesStarted = false;
|
||||||
|
static bool bootForceSetup = false;
|
||||||
|
static unsigned long nightDarkSinceMs = 0;
|
||||||
|
|
||||||
static constexpr float DIM_LUX_MIN = 0.0f;
|
static constexpr float DIM_LUX_MIN = 0.0f;
|
||||||
static constexpr float DIM_LUX_MAX = 300.0f;
|
static constexpr float DIM_LUX_MAX = 300.0f;
|
||||||
@@ -55,6 +60,10 @@ static constexpr uint8_t DIM_CONTRAST_MIN = 0x10;
|
|||||||
static constexpr uint8_t DIM_CONTRAST_MAX = 0xFF;
|
static constexpr uint8_t DIM_CONTRAST_MAX = 0xFF;
|
||||||
static constexpr int ROUTINE_WINDOW_MIN = 5;
|
static constexpr int ROUTINE_WINDOW_MIN = 5;
|
||||||
static constexpr unsigned long MOTION_WAKE_MS = 30000UL;
|
static constexpr unsigned long MOTION_WAKE_MS = 30000UL;
|
||||||
|
static constexpr float NIGHT_LUX_THRESHOLD = 8.0f;
|
||||||
|
static constexpr unsigned long NIGHT_DWELL_MS = 5UL * 60UL * 1000UL;
|
||||||
|
static constexpr uint32_t NIGHT_SLEEP_SECONDS = 30UL * 60UL;
|
||||||
|
static constexpr uint32_t BATTERY_SLEEP_SECONDS = 60UL * 60UL;
|
||||||
static constexpr int PIN_RESTART_BUTTON = 2; // Active-low button to GND
|
static constexpr int PIN_RESTART_BUTTON = 2; // Active-low button to GND
|
||||||
static constexpr unsigned long BUTTON_DEBOUNCE_MS = 30UL;
|
static constexpr unsigned long BUTTON_DEBOUNCE_MS = 30UL;
|
||||||
static constexpr unsigned long BUTTON_HOLD_RESTART_MS = 1200UL;
|
static constexpr unsigned long BUTTON_HOLD_RESTART_MS = 1200UL;
|
||||||
@@ -98,6 +107,31 @@ static int8_t rollToFaceSlideX(float rollDeg) {
|
|||||||
return (int8_t)v;
|
return (int8_t)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool shouldNightSleepFromAmbient(bool pluggedIn) {
|
||||||
|
if (!pluggedIn || !ambient.available()) {
|
||||||
|
nightDarkSinceMs = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lux = ambient.filteredLux();
|
||||||
|
if (lux < NIGHT_LUX_THRESHOLD) {
|
||||||
|
if (nightDarkSinceMs == 0) nightDarkSinceMs = millis();
|
||||||
|
return (millis() - nightDarkSinceMs) >= NIGHT_DWELL_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
nightDarkSinceMs = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startNetworkServices(bool forceSetup) {
|
||||||
|
if (networkServicesStarted) return;
|
||||||
|
|
||||||
|
wifi.begin(settings, forceSetup);
|
||||||
|
web.begin(settings, wifi, moisture, motion, face, webhook, bootMs);
|
||||||
|
ota.begin(web.server(), &display);
|
||||||
|
networkServicesStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void initRestartButton() {
|
static void initRestartButton() {
|
||||||
pinMode(PIN_RESTART_BUTTON, INPUT_PULLUP);
|
pinMode(PIN_RESTART_BUTTON, INPUT_PULLUP);
|
||||||
bool raw = digitalRead(PIN_RESTART_BUTTON);
|
bool raw = digitalRead(PIN_RESTART_BUTTON);
|
||||||
@@ -280,7 +314,6 @@ static void updateScheduleState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void updateAmbientDimming() {
|
static void updateAmbientDimming() {
|
||||||
ambient.loop();
|
|
||||||
if (!ambient.available() || !display.ok() || isNightMode || !display.displayEnabled()) return;
|
if (!ambient.available() || !display.ok() || isNightMode || !display.displayEnabled()) return;
|
||||||
|
|
||||||
float lux = ambient.filteredLux();
|
float lux = ambient.filteredLux();
|
||||||
@@ -312,23 +345,28 @@ void App::setup() {
|
|||||||
display.showStatus("FacePlant", "Starting...");
|
display.showStatus("FacePlant", "Starting...");
|
||||||
initRestartButton();
|
initRestartButton();
|
||||||
|
|
||||||
wifi.begin(settings, forceSetup);
|
|
||||||
|
|
||||||
moisture.begin(settings);
|
moisture.begin(settings);
|
||||||
battery.begin();
|
battery.begin();
|
||||||
|
power.begin(bootMs);
|
||||||
|
power.setBatteryAwakeWindowMs(2UL * 60UL * 1000UL);
|
||||||
|
power.loop(battery); // initialize plug state before deciding service startup
|
||||||
ambient.begin();
|
ambient.begin();
|
||||||
motion.begin();
|
motion.begin();
|
||||||
face.begin(display, settings);
|
face.begin(display, settings);
|
||||||
|
|
||||||
webhook.begin(settings);
|
webhook.begin(settings);
|
||||||
|
bootForceSetup = forceSetup;
|
||||||
|
|
||||||
{
|
{
|
||||||
MotionCalibration mc = settings.motionCalibration();
|
MotionCalibration mc = settings.motionCalibration();
|
||||||
motion.setZeroOffsets(mc.rollZeroDeg, mc.pitchZeroDeg);
|
motion.setZeroOffsets(mc.rollZeroDeg, mc.pitchZeroDeg);
|
||||||
}
|
}
|
||||||
|
|
||||||
web.begin(settings, wifi, moisture, motion, face, webhook, bootMs);
|
if (bootForceSetup || power.isPluggedIn()) {
|
||||||
ota.begin(web.server(), &display);
|
startNetworkServices(bootForceSetup);
|
||||||
|
} else {
|
||||||
|
Serial.println("[Power] Booting on battery - network services deferred");
|
||||||
|
}
|
||||||
|
|
||||||
lastMood = face.mood();
|
lastMood = face.mood();
|
||||||
lastDead = face.isDeadMode();
|
lastDead = face.isDeadMode();
|
||||||
@@ -343,8 +381,21 @@ void App::loop() {
|
|||||||
BootTrigger::clearAfterStableUptime();
|
BootTrigger::clearAfterStableUptime();
|
||||||
handleRestartButton();
|
handleRestartButton();
|
||||||
|
|
||||||
|
moisture.loop();
|
||||||
|
battery.loop();
|
||||||
|
power.loop(battery);
|
||||||
|
ambient.loop();
|
||||||
|
|
||||||
|
bool pluggedIn = power.isPluggedIn();
|
||||||
|
if (!networkServicesStarted && (bootForceSetup || pluggedIn)) {
|
||||||
|
startNetworkServices(bootForceSetup);
|
||||||
|
bootForceSetup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (networkServicesStarted) {
|
||||||
wifi.loop();
|
wifi.loop();
|
||||||
web.loop();
|
web.loop();
|
||||||
|
}
|
||||||
|
|
||||||
motion.loop();
|
motion.loop();
|
||||||
if (motion.available()) {
|
if (motion.available()) {
|
||||||
@@ -376,8 +427,8 @@ void App::loop() {
|
|||||||
updateAmbientDimming();
|
updateAmbientDimming();
|
||||||
|
|
||||||
// Show WiFi status on display during connection attempts
|
// Show WiFi status on display during connection attempts
|
||||||
bool currentConnected = wifi.connected();
|
bool currentConnected = networkServicesStarted && wifi.connected();
|
||||||
if (currentConnected != lastConnected) {
|
if (networkServicesStarted && currentConnected != lastConnected) {
|
||||||
if (currentConnected) {
|
if (currentConnected) {
|
||||||
Serial.println("[App] WiFi connected - showing on display");
|
Serial.println("[App] WiFi connected - showing on display");
|
||||||
if (!displaySleeping) {
|
if (!displaySleeping) {
|
||||||
@@ -392,10 +443,10 @@ void App::loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastConnected = currentConnected;
|
lastConnected = currentConnected;
|
||||||
|
} else if (!networkServicesStarted) {
|
||||||
|
lastConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
moisture.loop();
|
|
||||||
battery.loop();
|
|
||||||
if (!displaySleeping) {
|
if (!displaySleeping) {
|
||||||
face.loop(moisture, battery);
|
face.loop(moisture, battery);
|
||||||
}
|
}
|
||||||
@@ -404,6 +455,7 @@ void App::loop() {
|
|||||||
FaceRenderer::Mood m = face.mood();
|
FaceRenderer::Mood m = face.mood();
|
||||||
bool dead = face.isDeadMode();
|
bool dead = face.isDeadMode();
|
||||||
|
|
||||||
|
if (networkServicesStarted && wifi.connected()) {
|
||||||
if (dead && !lastDead) {
|
if (dead && !lastDead) {
|
||||||
webhook.send(EVT_DEAD, moisture, dead, bootMs);
|
webhook.send(EVT_DEAD, moisture, dead, bootMs);
|
||||||
} else if (!dead && lastDead) {
|
} else if (!dead && lastDead) {
|
||||||
@@ -411,7 +463,24 @@ void App::loop() {
|
|||||||
} else if (!dead && m != lastMood) {
|
} else if (!dead && m != lastMood) {
|
||||||
webhook.send(moodToEvent(m), moisture, dead, bootMs);
|
webhook.send(moodToEvent(m), moisture, dead, bootMs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lastMood = m;
|
lastMood = m;
|
||||||
lastDead = dead;
|
lastDead = dead;
|
||||||
|
|
||||||
|
// Plugged-in ambient night sleep: if it's consistently dark, deep-sleep and wake later to re-check.
|
||||||
|
if (shouldNightSleepFromAmbient(pluggedIn)) {
|
||||||
|
display.showStatus("FacePlant", "Sleeping (night)");
|
||||||
|
delay(250);
|
||||||
|
power.deepSleepForSeconds(NIGHT_SLEEP_SECONDS, "night ambient", &display);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery mode: keep face awake while dry; otherwise sleep after a short awake window.
|
||||||
|
bool inSetupPortal = networkServicesStarted && (wifi.mode() == NET_AP_SETUP);
|
||||||
|
if (!pluggedIn && !inSetupPortal && m != FaceRenderer::DRY &&
|
||||||
|
power.batteryWindowElapsed(millis())) {
|
||||||
|
display.showStatus("FacePlant", "Sleeping (battery)");
|
||||||
|
delay(250);
|
||||||
|
power.deepSleepForSeconds(BATTERY_SLEEP_SECONDS, "battery idle", &display);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/power/PowerManager.cpp
Normal file
71
src/power/PowerManager.cpp
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#include "PowerManager.h"
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <esp_bt.h>
|
||||||
|
#include <esp_sleep.h>
|
||||||
|
|
||||||
|
void PowerManager::begin(unsigned long bootMs) {
|
||||||
|
_bootMs = bootMs;
|
||||||
|
_onBatterySinceMs = bootMs;
|
||||||
|
_pluggedIn = true;
|
||||||
|
_plugStateInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerManager::setBatteryAwakeWindowMs(unsigned long windowMs) {
|
||||||
|
_batteryAwakeWindowMs = windowMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PowerManager::detectPluggedIn(const BatterySensor& battery) const {
|
||||||
|
// Primary signal: positive charge rate from MAX17048.
|
||||||
|
if (battery.isCharging()) return true;
|
||||||
|
|
||||||
|
// Fallback for topped-off battery where charge rate can read near zero while still plugged.
|
||||||
|
return (battery.percent() >= 98) && (battery.voltage() >= 4.15f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerManager::loop(const BatterySensor& battery) {
|
||||||
|
bool pluggedNow = detectPluggedIn(battery);
|
||||||
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
if (!_plugStateInitialized) {
|
||||||
|
_plugStateInitialized = true;
|
||||||
|
_pluggedIn = pluggedNow;
|
||||||
|
_onBatterySinceMs = pluggedNow ? _bootMs : now;
|
||||||
|
Serial.print("[Power] Initial state: ");
|
||||||
|
Serial.println(_pluggedIn ? "plugged-in" : "battery");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluggedNow == _pluggedIn) return;
|
||||||
|
_pluggedIn = pluggedNow;
|
||||||
|
|
||||||
|
if (_pluggedIn) {
|
||||||
|
Serial.println("[Power] Source changed: plugged-in");
|
||||||
|
} else {
|
||||||
|
_onBatterySinceMs = now;
|
||||||
|
Serial.println("[Power] Source changed: battery");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PowerManager::batteryWindowElapsed(unsigned long nowMs) const {
|
||||||
|
if (_pluggedIn) return false;
|
||||||
|
return (nowMs - _onBatterySinceMs) >= _batteryAwakeWindowMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PowerManager::deepSleepForSeconds(uint32_t seconds, const char* reason, Display* display) const {
|
||||||
|
Serial.print("[Power] Deep sleep: ");
|
||||||
|
Serial.print(reason);
|
||||||
|
Serial.print(" for ");
|
||||||
|
Serial.print(seconds);
|
||||||
|
Serial.println("s");
|
||||||
|
|
||||||
|
if (display && display->ok()) display->setDisplayEnabled(false);
|
||||||
|
|
||||||
|
WiFi.disconnect(true);
|
||||||
|
WiFi.mode(WIFI_OFF);
|
||||||
|
btStop();
|
||||||
|
|
||||||
|
esp_sleep_enable_timer_wakeup((uint64_t)seconds * 1000000ULL);
|
||||||
|
delay(50);
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
26
src/power/PowerManager.h
Normal file
26
src/power/PowerManager.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "../sensors/BatterySensor.h"
|
||||||
|
#include "../ui/Display.h"
|
||||||
|
|
||||||
|
class PowerManager {
|
||||||
|
public:
|
||||||
|
void begin(unsigned long bootMs);
|
||||||
|
void setBatteryAwakeWindowMs(unsigned long windowMs);
|
||||||
|
void loop(const BatterySensor& battery);
|
||||||
|
|
||||||
|
bool isPluggedIn() const { return _pluggedIn; }
|
||||||
|
bool batteryWindowElapsed(unsigned long nowMs) const;
|
||||||
|
|
||||||
|
void deepSleepForSeconds(uint32_t seconds, const char* reason, Display* display = nullptr) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool detectPluggedIn(const BatterySensor& battery) const;
|
||||||
|
|
||||||
|
bool _pluggedIn = true;
|
||||||
|
bool _plugStateInitialized = false;
|
||||||
|
unsigned long _bootMs = 0;
|
||||||
|
unsigned long _onBatterySinceMs = 0;
|
||||||
|
unsigned long _batteryAwakeWindowMs = 2UL * 60UL * 1000UL;
|
||||||
|
};
|
||||||
@@ -2,6 +2,14 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "../settings/Settings.h"
|
#include "../settings/Settings.h"
|
||||||
|
|
||||||
|
// Configurable via PlatformIO build flag: -D MOISTURE_ADC_PIN=<gpio>
|
||||||
|
// Defaults to GPIO3 if not provided.
|
||||||
|
#ifndef MOISTURE_ADC_PIN
|
||||||
|
#define MOISTURE_ADC_PIN 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr int PIN_MOISTURE = MOISTURE_ADC_PIN;
|
||||||
|
|
||||||
class MoistureSensor {
|
class MoistureSensor {
|
||||||
public:
|
public:
|
||||||
void begin(Settings& settings);
|
void begin(Settings& settings);
|
||||||
@@ -12,8 +20,6 @@ public:
|
|||||||
unsigned long lastUpdateMs() const { return _lastUpdateMs; }
|
unsigned long lastUpdateMs() const { return _lastUpdateMs; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int PIN_MOISTURE = 3;
|
|
||||||
|
|
||||||
Settings* _settings = nullptr;
|
Settings* _settings = nullptr;
|
||||||
|
|
||||||
static constexpr int NUM_SAMPLES = 12;
|
static constexpr int NUM_SAMPLES = 12;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ static void logExpectedI2CDevices() {
|
|||||||
|
|
||||||
void Display::begin() {
|
void Display::begin() {
|
||||||
Serial.println("[Display] begin()");
|
Serial.println("[Display] begin()");
|
||||||
|
Serial.print("[Display] Profile: ");
|
||||||
|
Serial.println(SCREEN_NAME);
|
||||||
Serial.print("[Display] SDA=");
|
Serial.print("[Display] SDA=");
|
||||||
Serial.print(PIN_SDA);
|
Serial.print(PIN_SDA);
|
||||||
Serial.print(" SCL=");
|
Serial.print(" SCL=");
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
#include <Adafruit_GFX.h>
|
#include <Adafruit_GFX.h>
|
||||||
#include <Adafruit_SH110X.h>
|
#include <Adafruit_SH110X.h>
|
||||||
|
|
||||||
|
#ifndef PB_OLED_SIZE
|
||||||
|
#define PB_OLED_SIZE 130
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (PB_OLED_SIZE != 96) && (PB_OLED_SIZE != 130) && (PB_OLED_SIZE != 240)
|
||||||
|
#error "PB_OLED_SIZE must be one of: 96, 130, 240"
|
||||||
|
#endif
|
||||||
|
|
||||||
class Display {
|
class Display {
|
||||||
public:
|
public:
|
||||||
void begin();
|
void begin();
|
||||||
@@ -20,9 +28,29 @@ public:
|
|||||||
private:
|
private:
|
||||||
static constexpr int PIN_SDA = 8;
|
static constexpr int PIN_SDA = 8;
|
||||||
static constexpr int PIN_SCL = 9;
|
static constexpr int PIN_SCL = 9;
|
||||||
static constexpr uint8_t OLED_ADDR = 0x3C; // try 0x3D if blank
|
|
||||||
Adafruit_SH1106G _oled = Adafruit_SH1106G(128, 64, &Wire, -1);
|
#if PB_OLED_SIZE == 96
|
||||||
|
static constexpr const char* SCREEN_NAME = "0.96in OLED";
|
||||||
|
static constexpr uint8_t OLED_ADDR = 0x3C;
|
||||||
|
static constexpr int OLED_WIDTH = 128;
|
||||||
|
static constexpr int OLED_HEIGHT = 64;
|
||||||
|
static constexpr uint8_t DEFAULT_CONTRAST = 0x9F;
|
||||||
|
#elif PB_OLED_SIZE == 130
|
||||||
|
static constexpr const char* SCREEN_NAME = "1.3in OLED";
|
||||||
|
static constexpr uint8_t OLED_ADDR = 0x3C;
|
||||||
|
static constexpr int OLED_WIDTH = 128;
|
||||||
|
static constexpr int OLED_HEIGHT = 64;
|
||||||
|
static constexpr uint8_t DEFAULT_CONTRAST = 0xCF;
|
||||||
|
#else
|
||||||
|
static constexpr const char* SCREEN_NAME = "2.4in OLED";
|
||||||
|
static constexpr uint8_t OLED_ADDR = 0x3C;
|
||||||
|
static constexpr int OLED_WIDTH = 128;
|
||||||
|
static constexpr int OLED_HEIGHT = 64;
|
||||||
|
static constexpr uint8_t DEFAULT_CONTRAST = 0xFF;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Adafruit_SH1106G _oled = Adafruit_SH1106G(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);
|
||||||
bool _ok = false;
|
bool _ok = false;
|
||||||
bool _displayEnabled = true;
|
bool _displayEnabled = true;
|
||||||
uint8_t _contrast = 0xCF;
|
uint8_t _contrast = DEFAULT_CONTRAST;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user