diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg b/usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg new file mode 100644 index 00000000..d518ca3e Binary files /dev/null and b/usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg differ diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png b/usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png new file mode 100644 index 00000000..cf146918 Binary files /dev/null and b/usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png differ diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/assets/readme.md b/usermods/Enclosure_with_OLED_temp_ESP07/assets/readme.md new file mode 100644 index 00000000..4d1005d9 --- /dev/null +++ b/usermods/Enclosure_with_OLED_temp_ESP07/assets/readme.md @@ -0,0 +1,7 @@ +# Enclosure and PCB + +## IP67 rated enclosure +![Enclosure](controller.jpg) + +## PCB +![PCB](pcb.png) diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/readme.md b/usermods/Enclosure_with_OLED_temp_ESP07/readme.md new file mode 100644 index 00000000..598c0c0a --- /dev/null +++ b/usermods/Enclosure_with_OLED_temp_ESP07/readme.md @@ -0,0 +1,36 @@ +# Almost universal controller board for outdoor applications +This usermod is using ideas from @mrVanboy and @400killer +## Features +* SSD1306 128x32 and 128x64 I2C OLED display +* On screen IP address, SSID and controller status (e.g. ON or OFF, recent effect) +* Auto display shutoff for saving display lifetime +* Dallas temperature sensor +* Reporting temperature to MQTT broker + +## Hardware +![Hardware connection](assets/controller.jpg) + +## Functionality checked with +* ESP-07S +* PlatformIO +* SSD1306 128x32 I2C OLED display +* DS18B20 (temperature sensor) +* KY-022 (infrared receiver) +* Push button (N.O. momentary switch) + +### Platformio requirements +Uncomment `U8g2@~2.27.3`,`DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`: +```ini +# platformio.ini +... +[common] +... +lib_deps_external = + ... + #For use SSD1306 0.91" OLED display uncomment following + U8g2@~2.27.3 + #For Dallas sensor uncomment following 2 lines + DallasTemperature@~3.8.0 + OneWire@~2.3.5 +... +``` diff --git a/usermods/Enclosure_with_OLED_temp_ESP07/wled06_usermod.ino b/usermods/Enclosure_with_OLED_temp_ESP07/wled06_usermod.ino new file mode 100644 index 00000000..b3f1c5db --- /dev/null +++ b/usermods/Enclosure_with_OLED_temp_ESP07/wled06_usermod.ino @@ -0,0 +1,212 @@ +#include // from https://github.com/olikraus/u8g2/ +#include //Dallastemperature sensor +//The SCL and SDA pins are defined here. +//Lolin32 boards use SCL=5 SDA=4 +#define U8X8_PIN_SCL 5 +#define U8X8_PIN_SDA 4 +// Dallas sensor +OneWire oneWire(12); +DallasTemperature sensor(&oneWire); +long temptimer = millis(); +long lastMeasure = 0; +#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit + +// If display does not work or looks corrupted check the +// constructor reference: +// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp +// or check the gallery: +// https://github.com/olikraus/u8g2/wiki/gallery +// --> First choise of cheap I2C OLED 128X32 +<<<<<<< HEAD +U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA +// --> Second choise of cheap I2C OLED 128X64 +//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA +======= +//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA +// --> Second choise of cheap I2C OLED 128X64 +U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA +>>>>>>> 1680c014057bb993974950f37b14369b398ca647 +// gets called once at boot. Do all initialization that doesn't depend on +// network here +void userSetup() { + sensor.begin(); //Start Dallas temperature sensor + u8x8.begin(); + u8x8.setPowerSave(0); + u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 + u8x8.setFont(u8x8_font_chroma48medium8_r); + u8x8.drawString(0, 0, "Loading..."); +} + +// gets called every time WiFi is (re-)connected. Initialize own network +// interfaces here +void userConnected() {} + +// needRedraw marks if redraw is required to prevent often redrawing. +bool needRedraw = true; + +// Next variables hold the previous known values to determine if redraw is +// required. +String knownSsid = ""; +IPAddress knownIp; +uint8_t knownBrightness = 0; +uint8_t knownMode = 0; +uint8_t knownPalette = 0; + +long lastUpdate = 0; +long lastRedraw = 0; +bool displayTurnedOff = false; +// How often we are redrawing screen +#define USER_LOOP_REFRESH_RATE_MS 5000 + +void userLoop() { + +//----> Dallas temperature sensor MQTT publishing + temptimer = millis(); +// Timer to publishe new temperature every 60 seconds + if (temptimer - lastMeasure > 60000) + { + lastMeasure = temptimer; +//Check if MQTT Connected, otherwise it will crash the 8266 + if (mqtt != nullptr) + { + sensor.requestTemperatures(); +//Gets prefered temperature scale based on selection in definitions section + #ifdef Celsius + float board_temperature = sensor.getTempCByIndex(0); + #else + float board_temperature = sensor.getTempFByIndex(0); + #endif +//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server. + char subuf[38]; + strcpy(subuf, mqttDeviceTopic); + strcat(subuf, "/temperature"); + mqtt->publish(subuf, 0, true, String(board_temperature).c_str()); + } + } + + // Check if we time interval for redrawing passes. + if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) { + return; + } + lastUpdate = millis(); + + // Turn off display after 3 minutes with no change. + if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) { + u8x8.setPowerSave(1); + displayTurnedOff = true; + } + + // Check if values which are shown on display changed from the last time. + if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) { + needRedraw = true; + } else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) { + needRedraw = true; + } else if (knownBrightness != bri) { + needRedraw = true; + } else if (knownMode != strip.getMode()) { + needRedraw = true; + } else if (knownPalette != strip.getSegment(0).palette) { + needRedraw = true; + } + + if (!needRedraw) { + return; + } + needRedraw = false; + + if (displayTurnedOff) + { + u8x8.setPowerSave(0); + displayTurnedOff = false; + } + lastRedraw = millis(); + + // Update last known values. + #if defined(ESP8266) + knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); + #else + knownSsid = WiFi.SSID(); + #endif + knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); + knownBrightness = bri; + knownMode = strip.getMode(); + knownPalette = strip.getSegment(0).palette; + u8x8.clear(); + u8x8.setFont(u8x8_font_chroma48medium8_r); + + // First row with Wifi name + u8x8.setCursor(1, 0); + u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); + // Print `~` char to indicate that SSID is longer, than owr dicplay + if (knownSsid.length() > u8x8.getCols()) + u8x8.print("~"); + + // Second row with IP or Psssword + u8x8.setCursor(1, 1); + // Print password in AP mode and if led is OFF. + if (apActive && bri == 0) + u8x8.print(apPass); + else + u8x8.print(knownIp); + + // Third row with mode name + u8x8.setCursor(2, 2); + uint8_t qComma = 0; + bool insideQuotes = false; + uint8_t printedChars = 0; + char singleJsonSymbol; + + // Find the mode name in JSON + for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) { + singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i); + switch (singleJsonSymbol) { + case '"': + insideQuotes = !insideQuotes; + break; + case '[': + case ']': + break; + case ',': + qComma++; + default: + if (!insideQuotes || (qComma != knownMode)) + break; + u8x8.print(singleJsonSymbol); + printedChars++; + } + if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2)) + break; + } + // Fourth row with palette name + u8x8.setCursor(2, 3); + qComma = 0; + insideQuotes = false; + printedChars = 0; + // Looking for palette name in JSON. + for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) { + singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i); + switch (singleJsonSymbol) { + case '"': + insideQuotes = !insideQuotes; + break; + case '[': + case ']': + break; + case ',': + qComma++; + default: + if (!insideQuotes || (qComma != knownPalette)) + break; + u8x8.print(singleJsonSymbol); + printedChars++; + } + if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2)) + break; + } + + u8x8.setFont(u8x8_font_open_iconic_embedded_1x1); + u8x8.drawGlyph(0, 0, 80); // wifi icon + u8x8.drawGlyph(0, 1, 68); // home icon + u8x8.setFont(u8x8_font_open_iconic_weather_2x2); + u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon +}