Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for I2C OLED Displays #52

Merged
merged 3 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions CO2_Gadget.ino
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/**/ // #define SUPPORT_OTA // Needs SUPPORT_WIFI - CURRENTLY NOT WORKING AWAITING FIX
/**/ #define SUPPORT_TFT
/**/ #define DEBUG_ARDUINOMENU
#define UNITHOSTNAME "CO2-Gadget"
/**/ #define UNITHOSTNAME "CO2-Gadget"
/**/ // #define ALTERNATIVE_I2C_PINS // For the compact build as shown at https://emariete.com/medidor-co2-display-tft-color-ttgo-t-display-sensirion-scd30/
/**/ #endif
/*****************************************************************************************************/
Expand All @@ -32,6 +32,7 @@ bool debugSensors = false;
bool inMenu = false;
bool bleInitialized = false;
int8_t selectedCO2Sensor = -1;
uint32_t DisplayBrightness = 100;

// Variables to control automatic display off to save power
bool displayOffOnExternalPower = false;
Expand All @@ -44,6 +45,16 @@ uint64_t lastButtonUpTimeStamp = millis(); // Last time button UP was pressed
#endif // ifdef BUILD_GIT
#define BUILD_GIT __DATE__

#undef I2C_SDA
#undef I2C_SCL
#ifdef ALTERNATIVE_I2C_PINS
#define I2C_SDA 22
#define I2C_SCL 21
#else
#define I2C_SDA 21
#define I2C_SCL 22
#endif

#include <Wire.h>
#include "driver/adc.h"
#include "soc/soc.h" // disable brownout problems
Expand Down Expand Up @@ -234,8 +245,8 @@ void displayLoop() {
return;

if (millis() > nextTimeToDisplayOff) {
Serial.println("-->[MAIN] Turning off display to save power");
setTFTBrightness(0); // Turn off the display
Serial.println("-->[MAIN] Turning off display to save power");
turnOffDisplay();
nextTimeToDisplayOff = nextTimeToDisplayOff + (timeToDisplayOff * 1000);
}
}
Expand All @@ -257,9 +268,10 @@ void setup() {
initPreferences();
initBattery();
#if defined SUPPORT_OLED
delay(100);
initDisplayOLED();
delay(1000);
displaySplashScreenOLED();
delay(1000);
#endif
#if defined SUPPORT_TFT
initDisplayTFT();
Expand Down Expand Up @@ -291,5 +303,5 @@ void loop() {
#endif
displayLoop();
buttonsLoop();
nav.poll(); // this device only draws when needed
menuLoop();
}
7 changes: 6 additions & 1 deletion CO2_Gadget_Buttons.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ Button2 btnUp(BTN_UP); // Initialize the up button
Button2 btnDwn(BTN_DWN); // Initialize the down button

void IRAM_ATTR buttonUpISR() {
setTFTBrightness(TFTBrightness); // Turn on the display at TFTBrightness brightness
#ifdef SUPPORT_TFT
setTFTBrightness(DisplayBrightness); // Turn on the display at DisplayBrightness brightness
#endif
#ifdef SUPPORT_OLED
setOLEDBrightness(DisplayBrightness); // Turn on the display at DisplayBrightness brightness
#endif
nextTimeToDisplayOff = millis() + (timeToDisplayOff*1000);
}

Expand Down
114 changes: 93 additions & 21 deletions CO2_Gadget_Menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@
// clang-format on
#include <menu.h>
#include <menuIO/serialIO.h>

#ifdef SUPPORT_TFT
#include <menuIO/TFT_eSPIOut.h>
// #include <menuIO/chainStream.h>
#endif

#ifdef SUPPORT_OLED
#include <menuIO/u8g2Out.h>
#include <menuIO/chainStream.h>
#endif

#include <menuIO/esp8266Out.h> //must include this even if not doing web output...

using namespace Menu;
Expand Down Expand Up @@ -195,12 +203,17 @@ result doSavePreferences(eventMask e, navNode &nav, prompt &item) {

result doSetTFTBrightness(eventMask e, navNode &nav, prompt &item) {
#ifdef DEBUG_ARDUINOMENU
Serial.printf("-->[MENU] Setting TFT brightness at %d", TFTBrightness);
Serial.printf("-->[MENU] Setting TFT brightness at %d", DisplayBrightness);
Serial.print(F("-->[MENU] action1 event:"));
Serial.println(e);
Serial.flush();
#endif
setTFTBrightness(TFTBrightness);
#ifdef SUPPORT_FTF
setTFTBrightness(DisplayBrightness);
#endif
#ifdef SUPPORT_OLED
setOLEDBrightness(DisplayBrightness);
#endif
return proceed;
}

Expand Down Expand Up @@ -507,7 +520,7 @@ TOGGLE(displayOffOnExternalPower, activeDisplayOffMenuOnBattery, "Off on USB: ",
,VALUE("OFF", false, doNothing, noEvent));

MENU(displayConfigMenu, "Display Config", doNothing, noEvent, wrapStyle
,FIELD(TFTBrightness, "Brightness:", "", 10, 255, 10, 10, doSetTFTBrightness, anyEvent, wrapStyle)
,FIELD(DisplayBrightness, "Brightness:", "", 10, 255, 10, 10, doSetTFTBrightness, anyEvent, wrapStyle)
,FIELD(timeToDisplayOff, "Time To Off:", "", 0, 900, 5, 5, doNothing, noEvent, wrapStyle)
,SUBMENU(activeDisplayOffMenuOnBattery)
,EXIT("<Back"));
Expand All @@ -528,8 +541,8 @@ MENU(configMenu, "Configuration", doNothing, noEvent, wrapStyle

MENU(informationMenu, "Information", doNothing, noEvent, wrapStyle
,FIELD(battery_voltage, "Battery", "V", 0, 9, 0, 0, doNothing, noEvent, noStyle)
,OP("Comp" BUILD_GIT, doNothing, noEvent)
,OP("Version" CO2_GADGET_VERSION CO2_GADGET_REV, doNothing, noEvent)
,OP("Comp " BUILD_GIT, doNothing, noEvent)
,OP("Version " CO2_GADGET_VERSION CO2_GADGET_REV, doNothing, noEvent)
,EDIT("IP", tempIPAddress, alphaNum, doNothing, noEvent, wrapStyle)
,EDIT("BLE Dev. Id", tempBLEDeviceId, alphaNum, doNothing, noEvent, wrapStyle)
,EXIT("<Back"));
Expand All @@ -555,8 +568,15 @@ MENU(mainMenu, "CO2 Gadget", doNothing, noEvent, wrapStyle
,SUBMENU(subMenu)
,EXIT("<Exit"));

#define MAX_DEPTH 4

serialIn serial(Serial);

// define serial output device
idx_t serialTops[MAX_DEPTH] = {0};
serialOut outSerial(Serial, serialTops);

#ifdef SUPPORT_TFT
// define menu colors --------------------------------------------------------
#define Black RGB565(0, 0, 0)
#define Red RGB565(255, 0, 0)
Expand Down Expand Up @@ -596,15 +616,6 @@ const colorDef<uint16_t> colors[6] MEMMODE = {
{{(uint16_t)White, (uint16_t)Gray}, {(uint16_t)Black, (uint16_t)Red, (uint16_t)White}}, // cursorColor
{{(uint16_t)White, (uint16_t)Yellow}, {(uint16_t)Black, (uint16_t)DarkerOrange, (uint16_t)Red}}, // titleColor - Menu title color
};
// clang-format on

#define MAX_DEPTH 4

serialIn serial(Serial);

// define serial output device
idx_t serialTops[MAX_DEPTH] = {0};
serialOut outSerial(Serial, serialTops);

#define tft_WIDTH 240
#define tft_HEIGHT 135
Expand All @@ -617,10 +628,49 @@ navNode *nodes[sizeof(panels) /
panelsList pList(panels, nodes, 1); // a list of panels and nodes
idx_t eSpiTops[MAX_DEPTH] = {0};
TFT_eSPIOut eSpiOut(tft, colors, eSpiTops, pList, fontW, fontH + 1);
menuOut *constMEM outputs[] MEMMODE = {&outSerial,
&eSpiOut}; // list of output devices
outputsList out(outputs,
sizeof(outputs) / sizeof(menuOut *)); // outputs list controller
menuOut *constMEM outputs[] MEMMODE = {&outSerial, &eSpiOut}; // list of output devices
outputsList out(outputs, sizeof(outputs) / sizeof(menuOut *)); // outputs list controller
#endif

#ifdef SUPPORT_OLED
// define menu colors --------------------------------------------------------
//each color is in the format:
// {{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
// this is a monochromatic color table
const colorDef<uint8_t> colors[6] MEMMODE={
{{0,0},{0,1,1}},//bgColor
{{1,1},{1,0,0}},//fgColor
{{1,1},{1,0,0}},//valColor
{{1,1},{1,0,0}},//unitColor
{{0,1},{0,0,1}},//cursorColor
{{1,1},{1,0,0}},//titleColor
};

#define fontX 5
#define fontY 10
// #define MENUFONT u8g2_font_7x13_mf
// #define fontX 7
// #define fontY 16
#define offsetX 1
#define offsetY 2
#define U8_Width 128
#define U8_Height 64
#define USE_HWI2C
#define fontMarginX 2
#define fontMarginY 2

//define output device oled
idx_t gfx_tops[MAX_DEPTH];
PANELS(gfxPanels,{0,0,U8_Width/fontX,U8_Height/fontY});
u8g2Out oledOut(u8g2,colors,gfx_tops,gfxPanels,fontX,fontY,offsetX,offsetY,fontMarginX,fontMarginY);

//define outputs controller
menuOut* outputs[]{&outSerial,&oledOut};//list of output devices
outputsList out(outputs,sizeof(outputs)/sizeof(menuOut*));//outputs list controller

MENU_INPUTS(in,&serial);
#endif
// clang-format on

NAVROOT(nav, mainMenu, MAX_DEPTH, serial, out);

Expand Down Expand Up @@ -733,7 +783,6 @@ void loadTempArraysWithActualValues() {

// when menu is suspended
result idle(menuOut &o, idleEvent e) {
#if defined SUPPORT_TFT
if (e == idleStart) {
#ifdef DEBUG_ARDUINOMENU
Serial.println("-->[MENU] Event idleStart");
Expand All @@ -745,7 +794,12 @@ result idle(menuOut &o, idleEvent e) {
Serial.println("-->[MENU] Event iddling");
Serial.flush();
#endif
#if defined SUPPORT_TFT
showValuesTFT(co2);
#endif
#if defined SUPPORT_OLED
showValuesOLED(co2);
#endif
readBatteryVoltage();
} else if (e == idleEnd) {
#ifdef DEBUG_ARDUINOMENU
Expand All @@ -762,11 +816,29 @@ result idle(menuOut &o, idleEvent e) {
#endif
}
return proceed;
}

void menuLoop() {
#ifdef SUPPORT_TFT
nav.poll(); // this device only draws when needed
#endif

#ifdef SUPPORT_OLED
nav.doInput();
if (nav.sleepTask) {
showValuesOLED(co2);
} else {
if (nav.changed(0)) {
u8g2.firstPage();
do nav.doOutput();
while (u8g2.nextPage());
}
}
#endif
}

void menu_init() {
nav.idleTask = idle; // function to be used when menu is suspended
nav.idleTask = idle; // function to be called when menu is suspended
nav.idleOn(idle);
nav.timeOut = 30;
nav.showTitle = true;
Expand Down
107 changes: 63 additions & 44 deletions CO2_Gadget_OLED.h
Original file line number Diff line number Diff line change
@@ -1,60 +1,79 @@

#ifndef CO2_Gadget_OLED_h
#define CO2_Gadget_OLED_h

#ifdef SUPPORT_OLED

// clang-format off
/*****************************************************************************************************/
/********* *********/
/********* SETUP OLED DISPLAY FUNCTIONALITY *********/
/********* *********/
/*****************************************************************************************************/
// clang-format on
#if defined SUPPORT_OLED
#include <U8x8lib.h>
U8X8_SH1106_128X64_NONAME_HW_I2C u8x8(/* reset=*/U8X8_PIN_NONE);
// #include <U8x8lib.h>
#include <U8g2lib.h>
#include "bootlogo.h"
#include "icons.h"
// U8X8_SH1106_128X64_NONAME_HW_I2C u8g2(/* reset=*/U8X8_PIN_NONE);
// U8G2_SSD1306_128X64_NONAME_HW_I2C u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
// U8G2_SSD1306_128X64_VCOMH0_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, I2C_SCL, I2C_SDA);//allow contrast change
// U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, I2C_SCL, I2C_SDA);
// U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Frame Buffer: clearBuffer/sendBuffer. More RAM usage, Faster
// U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Page Buffer: firstPage/nextPage. Less RAM usage, Slower

char oled_msg[20];
int displayWidth = 128;
int displayHeight = 64;
// #define MENUFONT u8g2_font_6x10_mf
#define MENUFONT u8g2_font_5x8_mf

void setOLEDBrightness(uint32_t newBrightness) {
Serial.printf("Setting screen brightness value at %d\n (unfunctional. TO DO", newBrightness);
}

#endif
void turnOffDisplay() {
setOLEDBrightness(0); // Turn off the display
}

void displaySplashScreenOLED() {
u8g2.clearDisplay();
u8g2.firstPage();
do {
// u8g2.drawXBMP(30, 0, 59, 20, eMarieteLogo);
// u8g2.drawXBM(7, 23, 46, 36, CO2Logo);
// u8g2.drawXBM(60, 32, 61, 23, GadgetLogo);
u8g2.drawXBM(0, 0, 128, 64, splash);
} while (u8g2.nextPage());
u8g2.setFont(MENUFONT);
}

void initDisplayOLED() {
#if defined SUPPORT_OLED
u8x8.begin();
u8x8.setPowerSave(0);
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0, 1, " eMariete.com");
u8x8.drawString(0, 2, " Sensirion");
u8x8.drawString(0, 3, "CO2 Gadget");
u8x8.drawString(0, 4, "Concentration Monitor");
#endif
Serial.printf("-->[OLED] Initialized: \t#%s#\n",
((u8g2.begin()) ? "OK" : "Failed"));
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_ncenB12_tr);
u8g2.drawStr(0, 15, " eMariete.com");
u8g2.drawStr(0, 33, " CO2 Gadget");
u8g2.drawStr(0, 51, " Air Quality");
} while (u8g2.nextPage());
u8g2.setFont(MENUFONT);
}

void showValuesOLED(uint16_t co2) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_7Segments_26x42_mn);
u8g2.setCursor(0, 44);
u8g2.print(co2);
u8g2.setFont(u8g2_font_5x7_tf);
u8g2.setCursor(110, 51);
u8g2.print("ppm");
} while (u8g2.nextPage());
u8g2.setFont(MENUFONT);
}

void showValuesOLED(String text) {
#if defined SUPPORT_OLED
u8x8.clearLine(2);
u8x8.clearLine(3);
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0, 4, "CO2: ");
u8x8.setFont(u8x8_font_courB18_2x3_r);
sprintf(oled_msg, "%4d", co2); // If parameter string then: co2.c_str()
u8x8.drawString(4, 3, oled_msg);
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(12, 4, "ppm");

u8x8.clearLine(6);
sprintf(oled_msg, "T:%.1fC RH:%.0f%%", temp, hum);
u8x8.drawUTF8(0, 6, oled_msg);

if (activeWIFI) {
if (WiFiMulti.run() != WL_CONNECTED) {
u8x8.clearLine(7);
u8x8.drawUTF8(0, 6, "WiFi unconnected");
} else {
u8x8.clearLine(7);
IPAddress ip = WiFi.localIP();
sprintf(oled_msg, "%s", ip.toString().c_str());
// sprintf("IP:%u.%u.%u.%u\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) &
// 0xff, ip >> 24);
u8x8.drawString(0, 7, oled_msg);
}
}
#endif
}
#endif // SUPPORT_OLED
#endif // CO2_Gadget_OLED_h
Loading