diff --git a/.gitignore b/.gitignore index 0f94f62..9b835ba 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,6 @@ **/.piolibdeps/ **/lib/ **/src/ +/build/ **/platformio.ini /secrets.yaml diff --git a/README.md b/README.md index 8b1f5e4..9558be2 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ > ### [Pool Pumps](./devices/pool_pumps.yaml) > This is a [Shelly 2.5 Double Relay Switch](https://www.amazon.com/gp/product/B07RRD13DJ/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) that is controlling the main pump on my pool and the auxillary pump that runs the pool cleaner. It turns the pump on and off through out the day and off at night (when we are least likely to be using the pool and when you get the most heat/water loss if the pump is running) and turns on the cleaner for a couple of hours in the morning. It also has some modes for Off (during the winter) and Continous when I need extra cleaning. -> ### [Scripture of the Day](./devices/scripture_of_the_day.yaml) -> This is a project I just started working on (and I am still waiting on the hardware to arrive from China). I am planning on building 2 of them as Christmas presents for my wife and son. It will consist of a [ESP8266 e-Paper Panel Driver Board](https://www.waveshare.com/e-paper-esp8266-driver-board.htm) powered by a [lithium battery](https://www.amazon.com/dp/B0867KDMY7/?coliid=IE0LBNACFHG4U&colid=1LOK862UA8LA0&psc=1&ref_=lv_ov_lig_dp_it) and [TP4056 lithium battery charger module](https://www.amazon.com/dp/B06XQRQR3Q/?coliid=I1B2ELKKLLKAK0&colid=1LOK862UA8LA0&psc=1&ref_=lv_ov_lig_dp_it) and driving a [Waveshare 7.5inch 800×480 E-Ink display](https://www.waveshare.com/7.5inch-e-paper.htm) all mounted inside a picture frame. The plan is to have it sit in deep-sleep most of the time but wake up every night, grab a random scripture from the [Our Manna Daily Verses API](http://www.ourmanna.com/verses/api/), update the display with the verse, and go back to sleep. +> ### [Scripture of the Day Melissa](./devices/scripture_of_the_day_melissa.yaml)/[Scripture of the Day Mayson](./devices/scripture_of_the_day_mayson.yaml) +> This is a project I just started working on recently, the code is complete but the build is not quite done. I am planning on building 2 of them as Christmas presents for my wife and son. It will consist of a [ESP32 e-Paper Panel Driver Board](https://www.waveshare.com/product/displays/e-paper-esp32-driver-board.htm) powered by a [lithium battery](https://www.amazon.com/dp/B0867KDMY7/?coliid=IE0LBNACFHG4U&colid=1LOK862UA8LA0&psc=1&ref_=lv_ov_lig_dp_it) and [TP4056 lithium battery charger module](https://www.amazon.com/dp/B06XQRQR3Q/?coliid=I1B2ELKKLLKAK0&colid=1LOK862UA8LA0&psc=1&ref_=lv_ov_lig_dp_it) and driving a [Waveshare 7.5inch 800×480 E-Ink display](https://www.waveshare.com/7.5inch-e-paper.htm) all mounted inside a wood frame I am building. The plan is to have it sit in deep-sleep most of the time but wake up every night, grab a random scripture from the [Our Manna Daily Verses API](http://www.ourmanna.com/verses/api/), update the display with the verse, and go back to sleep. ## Switches > I plan to use dimmer switches for anything that is dimmable just for consistency and you never know when you might want to have the ability to dim a light. However there are times when a dimmer isn't an option. diff --git a/components/wifi/wifi_dhcp.yaml b/components/wifi/wifi_dhcp.yaml new file mode 100644 index 0000000..142f2a0 --- /dev/null +++ b/components/wifi/wifi_dhcp.yaml @@ -0,0 +1,9 @@ +wifi: + ssid: ${wifi_ssid} + password: ${wifi_password} + fast_connect: true + power_save_mode: none + ap: + ssid: ${device_id} + +captive_portal: \ No newline at end of file diff --git a/custom/scripture_of_the_day.h b/custom/scripture_of_the_day.h new file mode 100644 index 0000000..d14da9c --- /dev/null +++ b/custom/scripture_of_the_day.h @@ -0,0 +1,146 @@ +#include "esphome.h" +#include +#include + +using namespace esphome; + +#define SCRIPTURE_URL "http://beta.ourmanna.com/api/v1/get/?format=json&order=random" +#define MAX_VERSE_LINES 8 +#define MAX_CHAR_PER_LINE 35 +#define STARTING_POSITION 40 +#define SPACE_BETWEEN_LINES 50 +#define JSON_BUFFER_SIZE (JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(1)) + +class ScriptureOfTheDay : public Component { + public: + float get_setup_priority() const override { return setup_priority::LATE; } + void setup() override { update_at_ = millis() + 4000; } + void loop() override; + + void set_http_request(http_request::HttpRequestComponent *http_request) { http_request_ = http_request; } + void set_display(waveshare_epaper::WaveshareEPaper *display) { display_ = display; } + void set_deep_sleep(deep_sleep::DeepSleepComponent *deep_sleep) { deep_sleep_ = deep_sleep; } + void set_sntp(sntp::SNTPComponent *sntp) { sntp_ = sntp; } + void set_fonts(display::Font *verse_font, display::Font *reference_font) { verse_font_ = verse_font; reference_font_ = reference_font; } + + void display_scripture(); + + protected: + http_request::HttpRequestComponent *http_request_; + waveshare_epaper::WaveshareEPaper *display_; + deep_sleep::DeepSleepComponent *deep_sleep_; + sntp::SNTPComponent *sntp_; + display::Font *verse_font_; + display::Font *reference_font_; + + std::vector scripture_; + uint64_t update_at_; + + std::vector get_scripture(); + std::vector split_verse_into_lines(std::string verse); + void shutdown(uint32_t sleepSeconds = 0); +}; + +void ScriptureOfTheDay::loop() +{ + // If we try to make the request to soon it fails so we delay 4 seconds + if (millis() > update_at_) + { + // If we get an especially long verse that won't fit on the display we try again. + do + { + scripture_ = get_scripture(); + } while (scripture_.size() > MAX_VERSE_LINES + 1); + + display_->update(); + + shutdown(); + } +} + +void ScriptureOfTheDay::display_scripture() +{ + if (scripture_.size() == 0) + { + return; + } + + int verseLineCount = scripture_.size() - 1; + int currentPosition = STARTING_POSITION + (SPACE_BETWEEN_LINES / 2) * (MAX_VERSE_LINES - verseLineCount); + for (int i = 0; i < verseLineCount; i++) + { + ESP_LOGD("Nuttytree", scripture_[i].c_str()); + display_->print(400, currentPosition, verse_font_, TextAlign::CENTER, scripture_[i].c_str()); + currentPosition += SPACE_BETWEEN_LINES; + } + + display_->print(760, currentPosition, reference_font_, TextAlign::CENTER_RIGHT, scripture_[verseLineCount].c_str()); +} + +std::vector ScriptureOfTheDay::get_scripture() +{ + http_request_->set_url(SCRIPTURE_URL); + http_request_->set_method("GET"); + + http_request_->send(); + if (http_request_->status_has_warning()) + { + // If the request failed we shutdown and try again in 15 minutes + shutdown(15 * 60); + } + const char *json = http_request_->get_string(); + + DynamicJsonBuffer jsonBuffer(JSON_BUFFER_SIZE); + JsonObject& scripture = jsonBuffer.parseObject(json); + + http_request_->close(); + + std::vector formattedScripture = split_verse_into_lines(std::string(scripture["verse"]["details"]["text"].as())); + formattedScripture.push_back(std::string(scripture["verse"]["details"]["reference"].as())); + + return formattedScripture; +} + +std::vector ScriptureOfTheDay::split_verse_into_lines(std::string verse) +{ + std::string word; + std::string currentLine; + std::vector lines; + std::istringstream ss(verse); + + while (ss >> word) + { + if (currentLine.length() == 0) + { + currentLine = word; + } + else if (currentLine.length() + word.length() < MAX_CHAR_PER_LINE) + { + currentLine += " " + word; + } + else + { + lines.push_back(currentLine); + currentLine = word; + } + } + + lines.push_back(currentLine); + + return lines; +} + +void ScriptureOfTheDay::shutdown(uint32_t sleepSeconds) +{ + if (sleepSeconds == 0) + { + // Wake back up and update at 3AM + time::ESPTime now = sntp_->now(); + sleepSeconds = 24 * 60 * 60 - (now.hour - 3) * 60 * 60 - now.minute * 60 - now.second; + } + + deep_sleep_->set_sleep_duration(sleepSeconds * 1000); + deep_sleep_->begin_sleep(true); +} + +ScriptureOfTheDay *Scripture; diff --git a/devices/.gitignore b/devices/.gitignore index 0bbf89c..e69de29 100644 --- a/devices/.gitignore +++ b/devices/.gitignore @@ -1,10 +0,0 @@ -# Gitignore settings for ESPHome -# This is an example and may include too much for your use-case. -# You can modify this file to suit your needs. -/.esphome/ -**/.pioenvs/ -**/.piolibdeps/ -**/lib/ -**/src/ -**/platformio.ini -/secrets.yaml diff --git a/devices/scripture_of_the_day.yaml b/devices/scripture_of_the_day.yaml deleted file mode 100644 index 004cd58..0000000 --- a/devices/scripture_of_the_day.yaml +++ /dev/null @@ -1,33 +0,0 @@ -substitutions: - device_id: scripture_of_the_day_1 - device_name: Scripture of the Day #1 - platform: ESP8266 - board: nodemcuv2 - ip_address: !secret master_bath_humidity_temp_sensor_ip - ota_pwd: !secret master_bath_humidity_temp_sensor_ota_pwd - api_pwd: !secret master_bath_humidity_temp_sensor_api_pwd - ap_wifi_pwd: !secret master_bath_humidity_temp_sensor_ap_wifi_pwd - -esphome: - <<: !include ../core/esphome.yaml - on_boot: - priority: -100 - then: - - http_request.get: - url: "https://beta.ourmanna.com/api/v1/get/?format=json&order=random" - verify_ssl: false - - lambda: |- - auto json = http_request_httprequestcomponent->get_string(); - -<<: !include ../components/logger/logger_debug.yaml - -<<: !include ../core/wifi_api_ota.yaml - -http_request: - -text_sensor: - - platform: template - id: scripture - - - platform: template - id: reference \ No newline at end of file diff --git a/devices/scripture_of_the_day_mayson.yaml b/devices/scripture_of_the_day_mayson.yaml new file mode 100644 index 0000000..1878861 --- /dev/null +++ b/devices/scripture_of_the_day_mayson.yaml @@ -0,0 +1,7 @@ +substitutions: + device_id: scripture_of_the_day_mayson + device_name: Scripture of the Day Mayson + log_level: debug + +packages: + device_base: !include ../packages/scripture_of_the_day.yaml diff --git a/devices/scripture_of_the_day_melissa.yaml b/devices/scripture_of_the_day_melissa.yaml new file mode 100644 index 0000000..2eef177 --- /dev/null +++ b/devices/scripture_of_the_day_melissa.yaml @@ -0,0 +1,7 @@ +substitutions: + device_id: scripture_of_the_day_melissa + device_name: Scripture of the Day Melissa + log_level: debug + +packages: + device_base: !include ../packages/scripture_of_the_day.yaml diff --git a/packages/scripture_of_the_day.yaml b/packages/scripture_of_the_day.yaml new file mode 100644 index 0000000..15a3c0c --- /dev/null +++ b/packages/scripture_of_the_day.yaml @@ -0,0 +1,75 @@ +substitutions: + platform: ESP32 + board: esp32dev + log_level: none + wifi_ssid: !secret wifi_ssid + wifi_password: !secret wifi_password + +esphome: + name: ${device_id} + platform: ${platform} + board: ${board} + arduino_version: latest + build_path: ../build/${device_id} + includes: + - ../custom/scripture_of_the_day.h +# on_boot: +# priority: -100 +# then: +# - delay: 4s +# - lambda: Scripture->update_scripture(); + +<<: !include ../components/wifi/wifi_dhcp.yaml + +<<: !include ../components/logger/logger.yaml + +custom_component: +- lambda: |- + Scripture = new ScriptureOfTheDay(); + Scripture->set_http_request(http_cmp); + Scripture->set_display(the_display); + Scripture->set_deep_sleep(deep_sleep_cmp); + Scripture->set_sntp(sntp_cmp); + Scripture->set_fonts(verse_font, reference_font); + return {Scripture}; + +# Setting run duration to 15s, if we aren't done by then something went wrong so we restart to save battery +# Setting a default sleep time of 15min that will only apply if we forced a shutdown after the 15s run duration +deep_sleep: + id: deep_sleep_cmp + run_duration: 15s + sleep_duration: 15min + +display: + - platform: waveshare_epaper + id: the_display + cs_pin: 15 + dc_pin: 27 + busy_pin: 25 + reset_pin: 26 + update_interval: 600s + model: 7.50inV2 + lambda: |- + Scripture->display_scripture(); + +font: + - file: "c:/windows/fonts/segoeprb.ttf" + id: verse_font + size: 35 + glyphs: "~!&-;:\"',.?’—“”0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz" + - file: "c:/windows/fonts/segoeprb.ttf" + id: reference_font + size: 30 + glyphs: "-:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz" + +http_request: + id: http_cmp + +spi: + clk_pin: 13 + mosi_pin: 14 + +time: + - platform: sntp + id: sntp_cmp + timezone: America/Chicago \ No newline at end of file