2024-04-03 11:40:46 +07:00
|
|
|
#include "AgOledDisplay.h"
|
2024-04-04 18:35:15 +07:00
|
|
|
#include "Libraries/U8g2/src/U8g2lib.h"
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/** Cast U8G2 */
|
2024-04-03 21:26:04 +07:00
|
|
|
#define DISP() ((U8G2_SH1106_128X64_NONAME_F_HW_I2C *)(this->u8g2))
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Show dashboard temperature and humdity
|
|
|
|
*
|
|
|
|
* @param hasStatus
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::showTempHum(bool hasStatus) {
|
2024-04-03 21:26:04 +07:00
|
|
|
char buf[10];
|
|
|
|
if (value.Temperature > -1001) {
|
|
|
|
if (config.isTemperatureUnitInF()) {
|
|
|
|
float tempF = (value.Temperature * 9) / 5 + 32;
|
2024-04-04 18:35:15 +07:00
|
|
|
if (hasStatus) {
|
|
|
|
snprintf(buf, sizeof(buf), "%0.1f", tempF);
|
|
|
|
} else {
|
|
|
|
snprintf(buf, sizeof(buf), "%0.1f°F", tempF);
|
|
|
|
}
|
2024-04-03 21:26:04 +07:00
|
|
|
} else {
|
2024-04-04 18:35:15 +07:00
|
|
|
if (hasStatus) {
|
|
|
|
snprintf(buf, sizeof(buf), "%.1f", value.Temperature);
|
|
|
|
} else {
|
|
|
|
snprintf(buf, sizeof(buf), "%.1f°C", value.Temperature);
|
|
|
|
}
|
2024-04-03 21:26:04 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-04-04 18:35:15 +07:00
|
|
|
if (config.isTemperatureUnitInF()) {
|
|
|
|
snprintf(buf, sizeof(buf), "-°F");
|
2024-04-03 21:26:04 +07:00
|
|
|
} else {
|
|
|
|
snprintf(buf, sizeof(buf), "-°C");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DISP()->drawUTF8(1, 10, buf);
|
2024-04-03 11:40:46 +07:00
|
|
|
|
2024-04-03 21:26:04 +07:00
|
|
|
/** Show humidty */
|
|
|
|
if (value.Humidity >= 0) {
|
|
|
|
snprintf(buf, sizeof(buf), "%d%%", value.Humidity);
|
|
|
|
} else {
|
|
|
|
snprintf(buf, sizeof(buf), "%-%%");
|
|
|
|
}
|
2024-04-03 11:40:46 +07:00
|
|
|
|
2024-04-03 21:26:04 +07:00
|
|
|
if (value.Humidity > 99) {
|
|
|
|
DISP()->drawStr(97, 10, buf);
|
|
|
|
} else {
|
|
|
|
DISP()->drawStr(105, 10, buf);
|
|
|
|
}
|
2024-04-03 11:40:46 +07:00
|
|
|
}
|
|
|
|
|
2024-05-02 10:19:49 +07:00
|
|
|
void OledDisplay::setCentralText(int y, String text) {
|
|
|
|
setCentralText(y, text.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void OledDisplay::setCentralText(int y, const char *text) {
|
|
|
|
int x = (DISP()->getWidth() - DISP()->getStrWidth(text)) / 2;
|
|
|
|
DISP()->drawStr(x, y, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Construct a new Ag Oled Display:: Ag Oled Display object
|
|
|
|
*
|
|
|
|
* @param config AgConfiguration
|
2024-04-07 16:39:01 +07:00
|
|
|
* @param value Measurements
|
2024-04-05 06:39:59 +07:00
|
|
|
* @param log Serial Stream
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
OledDisplay::OledDisplay(Configuration &config, Measurements &value, Stream &log)
|
|
|
|
: PrintLog(log, "OledDisplay"), config(config), value(value) {}
|
2024-04-04 10:36:59 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Set AirGradient instance
|
|
|
|
*
|
|
|
|
* @param ag Point to AirGradient instance
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::setAirGradient(AirGradient *ag) { this->ag = ag; }
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
OledDisplay::~OledDisplay() {}
|
2024-04-03 11:40:46 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Initialize display
|
|
|
|
*
|
|
|
|
* @return true Success
|
|
|
|
* @return false Failure
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool OledDisplay::begin(void) {
|
2024-04-03 21:26:04 +07:00
|
|
|
if (isBegin) {
|
2024-04-03 11:40:46 +07:00
|
|
|
logWarning("Already begin, call 'end' and try again");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Create u8g2 instance */
|
|
|
|
u8g2 = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(U8G2_R0, U8X8_PIN_NONE);
|
2024-04-03 21:26:04 +07:00
|
|
|
if (u8g2 == NULL) {
|
2024-04-03 11:40:46 +07:00
|
|
|
logError("Create 'U8G2' failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Init u8g2 */
|
2024-04-03 21:26:04 +07:00
|
|
|
if (DISP()->begin() == false) {
|
2024-04-03 11:40:46 +07:00
|
|
|
logError("U8G2 'begin' failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-01 21:25:35 +07:00
|
|
|
setBrightness(config.getDisplayBrightness());
|
|
|
|
|
2024-04-03 11:40:46 +07:00
|
|
|
isBegin = true;
|
|
|
|
logInfo("begin");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief De-Initialize display
|
|
|
|
*
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::end(void) {
|
2024-04-03 21:26:04 +07:00
|
|
|
if (!isBegin) {
|
2024-04-03 11:40:46 +07:00
|
|
|
logWarning("Already end, call 'begin' and try again");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Free u8g2 */
|
2024-04-07 16:39:01 +07:00
|
|
|
delete DISP();
|
2024-04-03 11:40:46 +07:00
|
|
|
u8g2 = NULL;
|
|
|
|
|
|
|
|
isBegin = false;
|
|
|
|
logInfo("end");
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Show text on 3 line of display
|
|
|
|
*
|
|
|
|
* @param line1
|
|
|
|
* @param line2
|
|
|
|
* @param line3
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::setText(String &line1, String &line2, String &line3) {
|
2024-04-03 11:40:46 +07:00
|
|
|
setText(line1.c_str(), line2.c_str(), line3.c_str());
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Show text on 3 line of display
|
|
|
|
*
|
|
|
|
* @param line1
|
|
|
|
* @param line2
|
|
|
|
* @param line3
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::setText(const char *line1, const char *line2,
|
2024-04-03 21:26:04 +07:00
|
|
|
const char *line3) {
|
2024-04-03 11:40:46 +07:00
|
|
|
DISP()->firstPage();
|
2024-04-04 18:35:15 +07:00
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
DISP()->drawStr(1, 10, line1);
|
|
|
|
DISP()->drawStr(1, 30, line2);
|
|
|
|
DISP()->drawStr(1, 50, line3);
|
|
|
|
} while (DISP()->nextPage());
|
2024-04-03 11:40:46 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Set Text on 4 line
|
|
|
|
*
|
|
|
|
* @param line1
|
|
|
|
* @param line2
|
|
|
|
* @param line3
|
|
|
|
* @param line4
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::setText(String &line1, String &line2, String &line3,
|
2024-04-03 21:26:04 +07:00
|
|
|
String &line4) {
|
2024-04-03 11:40:46 +07:00
|
|
|
setText(line1.c_str(), line2.c_str(), line3.c_str(), line4.c_str());
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Set Text on 4 line
|
|
|
|
*
|
|
|
|
* @param line1
|
|
|
|
* @param line2
|
|
|
|
* @param line3
|
|
|
|
* @param line4
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::setText(const char *line1, const char *line2,
|
2024-04-03 21:26:04 +07:00
|
|
|
const char *line3, const char *line4) {
|
2024-04-03 11:40:46 +07:00
|
|
|
DISP()->firstPage();
|
2024-04-04 18:35:15 +07:00
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
DISP()->drawStr(1, 10, line1);
|
|
|
|
DISP()->drawStr(1, 25, line2);
|
|
|
|
DISP()->drawStr(1, 40, line3);
|
|
|
|
DISP()->drawStr(1, 55, line4);
|
|
|
|
} while (DISP()->nextPage());
|
2024-04-03 11:40:46 +07:00
|
|
|
}
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Update dashboard content
|
|
|
|
*
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::showDashboard(void) { showDashboard(NULL); }
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Update dashboard content and error status
|
|
|
|
*
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void OledDisplay::showDashboard(const char *status) {
|
2024-04-03 21:26:04 +07:00
|
|
|
char strBuf[10];
|
|
|
|
|
|
|
|
DISP()->firstPage();
|
2024-04-04 18:35:15 +07:00
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
if ((status == NULL) || (strlen(status) == 0)) {
|
|
|
|
showTempHum(false);
|
|
|
|
} else {
|
|
|
|
String strStatus = "Show status: " + String(status);
|
|
|
|
logInfo(strStatus);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
int strWidth = DISP()->getStrWidth(status);
|
2024-04-25 06:49:14 +07:00
|
|
|
DISP()->drawStr((DISP()->getWidth() - strWidth) / 2, 10, status);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Show WiFi NA*/
|
|
|
|
if (strcmp(status, "WiFi N/A") == 0) {
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
showTempHum(true);
|
|
|
|
}
|
2024-04-03 21:26:04 +07:00
|
|
|
}
|
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Draw horizonal line */
|
|
|
|
DISP()->drawLine(1, 13, 128, 13);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Show CO2 label */
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
DISP()->drawUTF8(1, 27, "CO2");
|
|
|
|
|
|
|
|
DISP()->setFont(u8g2_font_t0_22b_tf);
|
|
|
|
if (value.CO2 > 0) {
|
|
|
|
int val = 9999;
|
|
|
|
if (value.CO2 < 10000) {
|
|
|
|
val = value.CO2;
|
|
|
|
}
|
|
|
|
sprintf(strBuf, "%d", val);
|
|
|
|
} else {
|
|
|
|
sprintf(strBuf, "%s", "-");
|
2024-04-03 21:26:04 +07:00
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
DISP()->drawStr(1, 48, strBuf);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Show CO2 value index */
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
DISP()->drawStr(1, 61, "ppm");
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Draw vertical line */
|
|
|
|
DISP()->drawLine(45, 14, 45, 64);
|
|
|
|
DISP()->drawLine(82, 14, 82, 64);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Draw PM2.5 label */
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
DISP()->drawStr(48, 27, "PM2.5");
|
|
|
|
|
|
|
|
/** Draw PM2.5 value */
|
|
|
|
DISP()->setFont(u8g2_font_t0_22b_tf);
|
|
|
|
if (config.isPmStandardInUSAQI()) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (value.pm25_1 >= 0) {
|
|
|
|
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.pm25_1));
|
2024-04-04 18:35:15 +07:00
|
|
|
} else {
|
|
|
|
sprintf(strBuf, "%s", "-");
|
|
|
|
}
|
|
|
|
DISP()->drawStr(48, 48, strBuf);
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
DISP()->drawUTF8(48, 61, "AQI");
|
2024-04-03 21:26:04 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (value.pm25_1 >= 0) {
|
|
|
|
sprintf(strBuf, "%d", value.pm25_1);
|
2024-04-04 18:35:15 +07:00
|
|
|
} else {
|
|
|
|
sprintf(strBuf, "%s", "-");
|
|
|
|
}
|
|
|
|
DISP()->drawStr(48, 48, strBuf);
|
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
|
|
|
DISP()->drawUTF8(48, 61, "ug/m³");
|
2024-04-03 21:26:04 +07:00
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
|
|
|
|
/** Draw tvocIndexlabel */
|
2024-04-03 21:26:04 +07:00
|
|
|
DISP()->setFont(u8g2_font_t0_12_tf);
|
2024-04-04 18:35:15 +07:00
|
|
|
DISP()->drawStr(85, 27, "tvoc:");
|
|
|
|
|
|
|
|
/** Draw tvocIndexvalue */
|
|
|
|
if (value.TVOC >= 0) {
|
|
|
|
sprintf(strBuf, "%d", value.TVOC);
|
2024-04-03 21:26:04 +07:00
|
|
|
} else {
|
|
|
|
sprintf(strBuf, "%s", "-");
|
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
DISP()->drawStr(85, 39, strBuf);
|
2024-04-03 21:26:04 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
/** Draw NOx label */
|
|
|
|
DISP()->drawStr(85, 53, "NOx:");
|
|
|
|
if (value.NOx >= 0) {
|
|
|
|
sprintf(strBuf, "%d", value.NOx);
|
|
|
|
} else {
|
|
|
|
sprintf(strBuf, "%s", "-");
|
|
|
|
}
|
|
|
|
DISP()->drawStr(85, 63, strBuf);
|
|
|
|
} while (DISP()->nextPage());
|
2024-04-03 21:26:04 +07:00
|
|
|
}
|
2024-04-25 06:49:14 +07:00
|
|
|
|
2024-05-01 21:25:35 +07:00
|
|
|
void OledDisplay::setBrightness(int percent) {
|
|
|
|
DISP()->setContrast((127 * percent) / 100);
|
|
|
|
}
|
2024-05-02 10:19:49 +07:00
|
|
|
|
|
|
|
void OledDisplay::showNewFirmwareVersion(String version) {
|
|
|
|
DISP()->firstPage();
|
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
setCentralText(20, "Firmware Update");
|
|
|
|
setCentralText(40, "New version");
|
|
|
|
setCentralText(60, version.c_str());
|
|
|
|
} while (DISP()->nextPage());
|
|
|
|
}
|
|
|
|
|
|
|
|
void OledDisplay::showNewFirmwareUpdating(String percent) {
|
|
|
|
DISP()->firstPage();
|
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
setCentralText(20, "Firmware Update");
|
|
|
|
setCentralText(50, String("Updating... ") + percent + String("%"));
|
|
|
|
} while (DISP()->nextPage());
|
|
|
|
}
|
|
|
|
|
|
|
|
void OledDisplay::showNewFirmwareSuccess(String count) {
|
|
|
|
DISP()->firstPage();
|
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
setCentralText(20, "Firmware Update");
|
|
|
|
setCentralText(40, "Success");
|
|
|
|
setCentralText(60, String("Rebooting... ") + count);
|
|
|
|
} while (DISP()->nextPage());
|
|
|
|
}
|
|
|
|
|
|
|
|
void OledDisplay::showNewFirmwareFailed(void) {
|
|
|
|
DISP()->firstPage();
|
|
|
|
do {
|
|
|
|
DISP()->setFont(u8g2_font_t0_16_tf);
|
|
|
|
setCentralText(20, "Firmware Update");
|
|
|
|
setCentralText(40, "Failed");
|
|
|
|
setCentralText(60, String("Retry after 24h"));
|
|
|
|
} while (DISP()->nextPage());
|
|
|
|
}
|