diff --git a/.github/workflows/main.actions.yml b/.github/workflows/main.actions.yml index eebc641..172676f 100644 --- a/.github/workflows/main.actions.yml +++ b/.github/workflows/main.actions.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@master - uses: ArminJo/arduino-test-compile@v3 with: - arduino-board-fqbn: esp32:esp32:watchy:Revision=${{ matrix.board-revisions }},PartitionScheme=min_spiffs,UploadSpeed=921600,DebugLevel=none,EraseFlash=none + arduino-board-fqbn: esp32:esp32:watchy:Revision=${{ matrix.board-revisions }},PartitionScheme=huge_app,UploadSpeed=921600,DebugLevel=none,EraseFlash=none platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json arduino-platform: esp32:esp32@2.0.17 required-libraries: Adafruit GFX Library,Arduino_JSON,DS3232RTC,NTPClient,Rtc_Pcf8563,GxEPD2,WiFiManager @@ -36,4 +36,4 @@ jobs: - uses: softprops/action-gh-release@v1 with: name: "Watchy Arduino Library ${{ github.ref_name }}" - files: ${{ github.workspace }}/examples/WatchFaces/**/build/*.bin + files: ${{ github.workspace }}/examples/WatchFaces/**/build/*.bin \ No newline at end of file diff --git a/.github/workflows/v3.actions.yml b/.github/workflows/v3.actions.yml new file mode 100644 index 0000000..740557a --- /dev/null +++ b/.github/workflows/v3.actions.yml @@ -0,0 +1,39 @@ +name: ReleaseV3 +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" +jobs: + release: + name: Build and Release + runs-on: ubuntu-latest + strategy: + matrix: + board-revisions: [v30] + steps: + - uses: actions/checkout@master + - uses: ArminJo/arduino-test-compile@v3 + with: + arduino-board-fqbn: esp32:esp32:esp32s3:FlashSize=8M,PartitionScheme=default_8MB,UploadSpeed=921600,DebugLevel=none,EraseFlash=none + platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json + arduino-platform: esp32:esp32@2.0.17 + required-libraries: Adafruit GFX Library,Arduino_JSON,DS3232RTC,NTPClient,Rtc_Pcf8563,GxEPD2,WiFiManager + set-build-path: true + - name: Rename binaries with board revision + run: | + parent_dir="${{ github.workspace }}/examples/WatchFaces" + for dir in "$parent_dir"/*; do + if [ -d "$dir" ]; then + cd "$dir/build" + for file in *; do + name="${file%%.*}" + ext="${file#$name.}" + mv "$file" "$name-${{ matrix.board-revisions }}.$ext" + done + cd - + fi + done + - uses: softprops/action-gh-release@v1 + with: + name: "Watchy Arduino Library ${{ github.ref_name }}" + files: ${{ github.workspace }}/examples/WatchFaces/**/build/*.bin \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2c92209..27432d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +.pio/ +.vscode/ app/bin/ app/pde.jar build/macosx/work/ diff --git a/README.md b/README.md index cf9bcaa..5d4f070 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,15 @@ ![Watchy](https://watchy.sqfmi.com/img/watchy_render.png) -**Buy Watchy from [The Pi Hut](https://thepihut.com/collections/sqfmi), [Crowd Supply](https://www.crowdsupply.com/sqfmi/watchy), and [Mouser](https://www.mouser.com/ProductDetail/SQFMI/SQFMI-WATCHY-10?qs=DRkmTr78QARN9VSJRzqRxw%3D%3D)!** +**Buy Watchy from [Mouser](https://www.mouser.com/ProductDetail/SQFMI/SQFMI-WATCHY-10?qs=DRkmTr78QARN9VSJRzqRxw%3D%3D), [The Pi Hut](https://thepihut.com/collections/sqfmi), and [Crowd Supply](https://www.crowdsupply.com/sqfmi/watchy)** [**Watchy Case & Accessories**](https://shop.sqfmi.com) -Visit [**https://watchy.sqfmi.com**](https://watchy.sqfmi.com) for documentation, hardware design files, and more! - -## Setup -1. In the Arduino IDE Boards Manager, [install support for the ESP32](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html). - * Arduino > Preferences > Additional Board Manager URLs - * ```https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json``` -2. Install this library (search for **Watchy** in the library manager), and any other dependencies when prompted -3. Check out the examples under ```Examples``` -> ```Watchy``` -4. Compile & Upload with these board settings: - * Board: "Watchy" - * Partition Scheme: "Huge App" - * Board Revision: Choose your Watchy version - * All Other Settings: leave to default - -You may also have to install the [CP2104 USB to Serial drivers](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers) if the port is not automatically detected. +## Getting Started Guide +Follow the instructions here https://watchy.sqfmi.com/docs/getting-started ### Have Fun! :) - ### Got Questions? Join our [Discord](https://discord.gg/ZXDegGV8E7) diff --git a/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp b/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp index a0c628c..9ff254b 100644 --- a/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp +++ b/examples/WatchFaces/7_SEG/Watchy_7_SEG.cpp @@ -16,10 +16,15 @@ void Watchy7SEG::drawWatchFace(){ drawSteps(); drawWeather(); drawBattery(); - display.drawBitmap(120, 77, WIFI_CONFIGURED ? wifi : wifioff, 26, 18, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); + display.drawBitmap(116, 75, WIFI_CONFIGURED ? wifi : wifioff, 26, 18, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); if(BLE_CONFIGURED){ - display.drawBitmap(100, 75, bluetooth, 13, 21, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); + display.drawBitmap(100, 73, bluetooth, 13, 21, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); } + #ifdef ARDUINO_ESP32S3_DEV + if(USB_PLUGGED_IN){ + display.drawBitmap(140, 75, charge, 16, 18, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); + } + #endif } void Watchy7SEG::drawTime(){ @@ -81,25 +86,25 @@ void Watchy7SEG::drawSteps(){ display.println(stepCount); } void Watchy7SEG::drawBattery(){ - display.drawBitmap(154, 73, battery, 37, 21, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); - display.fillRect(159, 78, 27, BATTERY_SEGMENT_HEIGHT, DARKMODE ? GxEPD_BLACK : GxEPD_WHITE);//clear battery segments + display.drawBitmap(158, 73, battery, 37, 21, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); + display.fillRect(163, 78, 27, BATTERY_SEGMENT_HEIGHT, DARKMODE ? GxEPD_BLACK : GxEPD_WHITE);//clear battery segments int8_t batteryLevel = 0; float VBAT = getBatteryVoltage(); - if(VBAT > 4.1){ + if(VBAT > 4.0){ batteryLevel = 3; } - else if(VBAT > 3.95 && VBAT <= 4.1){ + else if(VBAT > 3.6 && VBAT <= 4.0){ batteryLevel = 2; } - else if(VBAT > 3.80 && VBAT <= 3.95){ + else if(VBAT > 3.20 && VBAT <= 3.6){ batteryLevel = 1; } - else if(VBAT <= 3.80){ + else if(VBAT <= 3.20){ batteryLevel = 0; } for(int8_t batterySegments = 0; batterySegments < batteryLevel; batterySegments++){ - display.fillRect(159 + (batterySegments * BATTERY_SEGMENT_SPACING), 78, BATTERY_SEGMENT_WIDTH, BATTERY_SEGMENT_HEIGHT, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); + display.fillRect(163 + (batterySegments * BATTERY_SEGMENT_SPACING), 78, BATTERY_SEGMENT_WIDTH, BATTERY_SEGMENT_HEIGHT, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); } } @@ -150,4 +155,4 @@ void Watchy7SEG::drawWeather(){ } display.drawBitmap(145, 158, weatherIcon, WEATHER_ICON_WIDTH, WEATHER_ICON_HEIGHT, DARKMODE ? GxEPD_WHITE : GxEPD_BLACK); -} +} \ No newline at end of file diff --git a/examples/WatchFaces/7_SEG/icons.h b/examples/WatchFaces/7_SEG/icons.h index 49ab826..9d67f76 100644 --- a/examples/WatchFaces/7_SEG/icons.h +++ b/examples/WatchFaces/7_SEG/icons.h @@ -189,6 +189,14 @@ const unsigned char wifioff [] PROGMEM = { 0x01, 0xff, 0xc0, 0x00, 0x07, 0xe1, 0xc0, 0x00, 0x0f, 0xc0, 0x80, 0x00, 0x1f, 0x0c, 0x00, 0x00, 0x3c, 0x1e, 0x00, 0x00, 0xf8, 0x0c, 0x00, 0x00 }; + +// 'charge', 16x18px +const unsigned char charge [] PROGMEM = { + 0x00, 0x10, 0x00, 0x70, 0x00, 0xe0, 0x01, 0xe0, 0x03, 0xe0, 0x07, 0xc0, 0x0f, 0xc0, 0x1f, 0xff, + 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x03, 0xf0, 0x03, 0xe0, 0x07, 0xc0, 0x07, 0x80, 0x07, 0x00, + 0x0e, 0x00, 0x0c, 0x00 +}; + // 'chip', 48x32px const unsigned char chip [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/library.json b/library.json index 24c321f..d81ceb3 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Watchy", - "version": "1.4.13", + "version": "1.4.14", "description": "Watchy - An Open Source E-Paper Watch by SQFMI", "authors": [ { @@ -30,7 +30,7 @@ }, { "name": "WiFiManager", - "version": "https://github.com/tzapu/WiFiManager.git#2.0.3-alpha" + "version": "https://github.com/tzapu/WiFiManager.git#master" } ] } diff --git a/library.properties b/library.properties index 18abeac..8cc9f86 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Watchy -version=1.4.13 +version=1.4.14 author=SQFMI maintainer=SQFMI sentence=Watchy - An Open Source E-Paper Watch by SQFMI diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..441f7d8 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,47 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + + +[env:base] +platform = espressif32@6.7.0 +framework = arduino +;CDC enabled on boot: +build_flags = -DCDC_ENABLED +;erase flash before upload: +;upload_flags = --erase-all +;upload speed: +upload_speed = 115200 +;upload port (put yours here): +upload_port = COM7 +;upload_port = /dev/ttyACM0 for linux +board_build.partitions = default_8MB.csv +monitor_speed = 115200 +lib_deps = + Adafruit GFX Library + Arduino_JSON + DS3232RTC + NTPClient + https://github.com/orbitalair/Rtc_Pcf8563.git#master + https://github.com/ZinggJM/GxEPD2.git#master + https://github.com/tzapu/WiFiManager.git#master + + +[env:esp32-s3-devkitc-1] +; This is for v3 +extends = env:base +board = esp32-s3-devkitc-1 +board_build.mcu = esp32s3 +framework = arduino + +[env:esp32-pico-devkitm-2] +; This is for v1, v1.5, v2 +extends = env:base +board = esp32-pico-devkitm-2 +framework = arduino \ No newline at end of file diff --git a/src/Display.cpp b/src/Display.cpp index ecaac83..6440e4c 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -19,11 +19,9 @@ RTC_DATA_ATTR bool displayFullInit = true; void WatchyDisplay::busyCallback(const void *) { - #ifndef ARDUINO_ESP32S3_DEV gpio_wakeup_enable((gpio_num_t)DISPLAY_BUSY, GPIO_INTR_LOW_LEVEL); esp_sleep_enable_gpio_wakeup(); esp_light_sleep_start(); - #endif } WatchyDisplay::WatchyDisplay() : @@ -50,15 +48,35 @@ void WatchyDisplay::asyncPowerOn() { } } -void WatchyDisplay::setDarkBorder(bool dark) { +void WatchyDisplay::drawDarkBorder(bool dark) { if (_hibernating) return; - darkBorder = dark; + //This line overrides the intended behaviour that I want for the + //darkBorder variable. I want to set the darkBorder variable to dark + //and then paint the border always dark, not always putting the opposite + //colour of the background, like it is done here. + //darkBorder = dark; _startTransfer(); _transferCommand(0x3C); // BorderWavefrom _transfer(dark ? 0x02 : 0x05); _endTransfer(); } +/* + This is a setter for the darkBorder variable. It sets the darkBorder. +*/ +void WatchyDisplay::setDarkBorder(bool dark) { + if (_hibernating) return; + darkBorder = dark; + drawDarkBorder(dark); +} + +/* + This is a getter for the darkBorder variable. It returns the darkBorder. +*/ +bool WatchyDisplay::isDarkBorder() { + return darkBorder; +} + void WatchyDisplay::clearScreen(uint8_t value) { writeScreenBuffer(value); diff --git a/src/Display.h b/src/Display.h index dcb7248..5549f01 100644 --- a/src/Display.h +++ b/src/Display.h @@ -38,7 +38,9 @@ class WatchyDisplay : public GxEPD2_EPD // constructor WatchyDisplay(); void initWatchy(); + void drawDarkBorder(bool darkBorder); void setDarkBorder(bool darkBorder); + bool isDarkBorder(); void asyncPowerOn(); void _PowerOnAsync(); bool waitingPowerOn = false; @@ -76,7 +78,7 @@ class WatchyDisplay : public GxEPD2_EPD void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0) - bool darkBorder = false; // adds a dark border outside the normal screen area + bool darkBorder = true; // adds a dark border outside the normal screen area static constexpr bool reduceBoosterTime = true; // Saves ~200ms private: diff --git a/src/TimezonesGMT.h b/src/TimezonesGMT.h new file mode 100644 index 0000000..4a51e32 --- /dev/null +++ b/src/TimezonesGMT.h @@ -0,0 +1,65 @@ +#ifndef TIMEZONES_GMT_H +#define TIMEZONES_GMT_H + + +// You don't need to change anything here to be able to set up GMT based time. +// If you set TIMEZONES_NON_GMT_OVERRIDE to 1 (as for get summer time and leaps), +// you must provide one location based timezone. +// 0: GMT, 1: Location timezone. + +// Visit the link below. + +#ifndef TIMEZONES_NON_GMT_OVERRIDE +#define TIMEZONES_NON_GMT_OVERRIDE 0 +#endif + +#define TIMEZONES_LENGTH 28 +#define TIMEZONES_SELECTED 0 + +typedef struct TZ { + const char* location; + const char* timezone; +} TZ; + + +#ifdef TIMEZONES_NON_GMT_OVERRIDE +// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv +static TZ tz_override = { + "Europe/Madrid", + "CET-1CEST,M3.5.0,M10.5.0/3" +}; +#endif + + +static TZ timeZones[] = { + {"Etc/GMT+0","GMT0"}, // 0 + {"Etc/GMT+1","<-01>1"}, // 1 + {"Etc/GMT+2","<-02>2"}, // 2 + {"Etc/GMT+3","<-03>3"}, // 3 + {"Etc/GMT+4","<-04>4"}, // 4 + {"Etc/GMT+5","<-05>5"}, // 5 + {"Etc/GMT+6","<-06>6"}, // 6 + {"Etc/GMT+7","<-07>7"}, // 7 + {"Etc/GMT+8","<-08>8"}, // 8 + {"Etc/GMT+9","<-09>9"}, // 9 + {"Etc/GMT+10","<-10>10"}, // 10 + {"Etc/GMT+11","<-11>11"}, // 11 + {"Etc/GMT+12","<-12>12"}, // 12 + {"Etc/GMT-0","GMT0"}, // 13 + {"Etc/GMT-1","<+01>-1"}, // 14 + {"Etc/GMT-2","<+02>-2"}, // 15 + {"Etc/GMT-3","<+03>-3"}, // 16 + {"Etc/GMT-4","<+04>-4"}, // 17 + {"Etc/GMT-5","<+05>-5"}, // 18 + {"Etc/GMT-6","<+06>-6"}, // 19 + {"Etc/GMT-7","<+07>-7"}, // 20 + {"Etc/GMT-8","<+08>-8"}, // 21 + {"Etc/GMT-9","<+09>-9"}, // 22 + {"Etc/GMT-10","<+10>-10"}, // 23 + {"Etc/GMT-11","<+11>-11"}, // 24 + {"Etc/GMT-12","<+12>-12"}, // 25 + {"Etc/GMT-13","<+13>-13"}, // 26 + {"Etc/GMT-14","<+14>-14"}, // 27 +}; + +#endif //TIMEZONES_GMT_H \ No newline at end of file diff --git a/src/Watchy.cpp b/src/Watchy.cpp index 893d459..172c246 100644 --- a/src/Watchy.cpp +++ b/src/Watchy.cpp @@ -17,8 +17,13 @@ RTC_DATA_ATTR bool WIFI_CONFIGURED; RTC_DATA_ATTR bool BLE_CONFIGURED; RTC_DATA_ATTR weatherData currentWeather; RTC_DATA_ATTR int weatherIntervalCounter = -1; +#ifdef GMT_OFFSET_SEC +RTC_DATA_ATTR long gmtOffset = GMT_OFFSET_SEC; +#else RTC_DATA_ATTR long gmtOffset = 0; +#endif RTC_DATA_ATTR bool alreadyInMenu = true; +RTC_DATA_ATTR bool USB_PLUGGED_IN = false; RTC_DATA_ATTR tmElements_t bootTime; RTC_DATA_ATTR uint32_t lastIPAddress; RTC_DATA_ATTR char lastSSID[30]; @@ -32,7 +37,6 @@ void Watchy::init(String datetime) { Wire.begin(SDA, SCL); // init i2c #endif RTC.init(); - // Init the display since is almost sure we will use it display.epd2.initWatchy(); @@ -57,7 +61,7 @@ void Watchy::init(String datetime) { // Return to watchface if in menu for more than one tick if (alreadyInMenu) { guiState = WATCHFACE_STATE; - showWatchFace(false); + showWatchFace(true); } else { alreadyInMenu = true; } @@ -67,9 +71,23 @@ void Watchy::init(String datetime) { case ESP_SLEEP_WAKEUP_EXT1: // button Press handleButtonPress(); break; + #ifdef ARDUINO_ESP32S3_DEV + case ESP_SLEEP_WAKEUP_EXT0: // USB plug in + pinMode(USB_DET_PIN, INPUT); + USB_PLUGGED_IN = (digitalRead(USB_DET_PIN) == 1); + if(guiState == WATCHFACE_STATE){ + RTC.read(currentTime); + showWatchFace(true); + } + break; + #endif default: // reset RTC.config(datetime); _bmaConfig(); + #ifdef ARDUINO_ESP32S3_DEV + pinMode(USB_DET_PIN, INPUT); + USB_PLUGGED_IN = (digitalRead(USB_DET_PIN) == 1); + #endif gmtOffset = settings.gmtOffset; RTC.read(currentTime); RTC.read(bootTime); @@ -85,9 +103,16 @@ void Watchy::deepSleep() { display.hibernate(); RTC.clearAlarm(); // resets the alarm flag in the RTC #ifdef ARDUINO_ESP32S3_DEV + esp_sleep_enable_ext0_wakeup((gpio_num_t)USB_DET_PIN, USB_PLUGGED_IN ? LOW : HIGH); //// enable deep sleep wake on USB plug in/out + rtc_gpio_set_direction((gpio_num_t)USB_DET_PIN, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pullup_en((gpio_num_t)USB_DET_PIN); + esp_sleep_enable_ext1_wakeup( BTN_PIN_MASK, ESP_EXT1_WAKEUP_ANY_LOW); // enable deep sleep wake on button press + rtc_gpio_set_direction((gpio_num_t)UP_BTN_PIN, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pullup_en((gpio_num_t)UP_BTN_PIN); + rtc_clk_32k_enable(true); //rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL); struct tm timeinfo; @@ -108,7 +133,6 @@ void Watchy::deepSleep() { BTN_PIN_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); // enable deep sleep wake on button press #endif - gpio_deep_sleep_hold_dis(); esp_deep_sleep_start(); } @@ -118,7 +142,7 @@ void Watchy::handleButtonPress() { if (wakeupBit & MENU_BTN_MASK) { if (guiState == WATCHFACE_STATE) { // enter menu state if coming from watch face - showMenu(menuIndex, false); + showMenu(menuIndex, true); } else if (guiState == MAIN_MENU_STATE) { // if already in menu, then select menu item switch (menuIndex) { @@ -154,11 +178,11 @@ void Watchy::handleButtonPress() { else if (wakeupBit & BACK_BTN_MASK) { if (guiState == MAIN_MENU_STATE) { // exit to watch face if already in menu RTC.read(currentTime); - showWatchFace(false); + showWatchFace(true); } else if (guiState == APP_STATE) { - showMenu(menuIndex, false); // exit to menu if already in app + showMenu(menuIndex, true); // exit to menu if already in app } else if (guiState == FW_UPDATE_STATE) { - showMenu(menuIndex, false); // exit to menu if already in app + showMenu(menuIndex, true); // exit to menu if already in app } else if (guiState == WATCHFACE_STATE) { return; } @@ -236,12 +260,12 @@ void Watchy::handleButtonPress() { if (guiState == MAIN_MENU_STATE) { // exit to watch face if already in menu RTC.read(currentTime); - showWatchFace(false); + showWatchFace(true); break; // leave loop } else if (guiState == APP_STATE) { - showMenu(menuIndex, false); // exit to menu if already in app + showMenu(menuIndex, true); // exit to menu if already in app } else if (guiState == FW_UPDATE_STATE) { - showMenu(menuIndex, false); // exit to menu if already in app + showMenu(menuIndex, true); // exit to menu if already in app } } else if (digitalRead(UP_BTN_PIN) == ACTIVE_LOW) { lastTimeout = millis(); @@ -375,7 +399,7 @@ void Watchy::showAbout() { }else{ display.println("WiFi Not Connected"); } - display.display(false); // full refresh + display.display(true); // full refresh guiState = APP_STATE; } @@ -387,9 +411,9 @@ void Watchy::showBuzz() { display.setTextColor(GxEPD_WHITE); display.setCursor(70, 80); display.println("Buzz!"); - display.display(false); // full refresh + display.display(true); // full refresh vibMotor(); - showMenu(menuIndex, false); + showMenu(menuIndex, true); } void Watchy::vibMotor(uint8_t intervalMs, uint8_t length) { @@ -419,8 +443,11 @@ void Watchy::setTime() { int8_t hour = currentTime.Hour; int8_t day = currentTime.Day; int8_t month = currentTime.Month; - int8_t year = tmYearToY2k(currentTime.Year); + int8_t year = currentTime.Year; //tmYearToY2k(currentTime.Year); #endif + int8_t gmt = gmtOffset / 3600; + + int8_t tzIndex = TIMEZONES_SELECTED; int8_t setIndex = SET_HOUR; @@ -467,6 +494,9 @@ void Watchy::setTime() { case SET_DAY: day == 31 ? (day = 1) : day++; break; + case SET_TZ: + tzIndex == TIMEZONES_LENGTH - 1 ? (tzIndex = 0) : tzIndex++; + break; default: break; } @@ -490,11 +520,23 @@ void Watchy::setTime() { case SET_DAY: day == 1 ? (day = 31) : day--; break; + case SET_TZ: + tzIndex == 0 ? (tzIndex = TIMEZONES_LENGTH - 1) : tzIndex--; + break; default: break; } } + + if(tzIndex < 13){ + gmt = (tzIndex); + }else if(tzIndex == 13){ + gmt = 0; + }else{ + gmt = - (tzIndex - 13); + } + display.fillScreen(GxEPD_BLACK); display.setTextColor(GxEPD_WHITE); display.setFont(&DSEG7_Classic_Bold_53); @@ -520,14 +562,25 @@ void Watchy::setTime() { } display.print(minute); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_WHITE); + + display.setCursor(82, 140); + if (setIndex == SET_TZ) { // blink minute digits + display.setTextColor(blink ? GxEPD_WHITE : GxEPD_BLACK); + } + + display.print("GMT"); + display.print(gmt); + display.setTextColor(GxEPD_WHITE); display.setFont(&FreeMonoBold9pt7b); - display.setCursor(45, 150); + display.setCursor(60, 165); if (setIndex == SET_YEAR) { // blink minute digits display.setTextColor(blink ? GxEPD_WHITE : GxEPD_BLACK); } - display.print(2000 + year); + display.print(year); display.setTextColor(GxEPD_WHITE); display.print("/"); @@ -550,6 +603,7 @@ void Watchy::setTime() { display.print("0"); } display.print(day); + display.display(true); // partial refresh } @@ -559,15 +613,27 @@ void Watchy::setTime() { #ifdef ARDUINO_ESP32S3_DEV tm.Year = year; #else - tm.Year = y2kYearToTm(year); + tm.Year = year; //y2kYearToTm(year); #endif tm.Hour = hour; tm.Minute = minute; tm.Second = 0; - RTC.set(tm); + gmtOffset = gmt * 3600; + + if(TIMEZONES_NON_GMT_OVERRIDE == 0){ + setenv("TZ", timeZones[tzIndex].timezone, 1); + } else if (TIMEZONES_NON_GMT_OVERRIDE == 1) { + setenv("TZ", tz_override.timezone, 1); + } else { + setenv("TZ", timeZones[TIMEZONES_SELECTED].timezone, 1); + } - showMenu(menuIndex, false); + tzset(); + + RTC.set(tm); + + showMenu(menuIndex, true); } void Watchy::showAccelerometer() { @@ -639,7 +705,7 @@ void Watchy::showAccelerometer() { } } - showMenu(menuIndex, false); + showMenu(menuIndex, true); } void Watchy::showWatchFace(bool partialRefresh) { @@ -709,7 +775,7 @@ weatherData Watchy::_getWeatherData(String cityID, String lat, String lon, Strin breakTime((time_t)(int)responseObject["sys"]["sunset"], currentWeather.sunset); // sync NTP during weather API call and use timezone of lat & lon gmtOffset = int(responseObject["timezone"]); - syncNTP(gmtOffset); + syncNTP(); } else { // http error } @@ -909,8 +975,9 @@ void Watchy::setupWifi() { weatherIntervalCounter = -1; // Reset to force weather to be read again lastIPAddress = WiFi.localIP(); WiFi.SSID().toCharArray(lastSSID, 30); + getWeatherData(); // force weather update } - display.display(false); // full refresh + display.display(true); // full refresh // turn off radios WiFi.mode(WIFI_OFF); btStop(); @@ -932,7 +999,7 @@ void Watchy::_configModeCallback(WiFiManager *myWiFiManager) { display.println(WiFi.softAPIP()); display.println("MAC address:"); display.println(WiFi.softAPmacAddress().c_str()); - display.display(false); // full refresh + display.display(true); // full refresh } bool Watchy::connectWiFi() { @@ -971,7 +1038,7 @@ void Watchy::showUpdateFW() { display.println("again when ready"); display.println(" "); display.println("Keep USB powered"); - display.display(false); // full refresh + display.display(true); // full refresh guiState = FW_UPDATE_STATE; } @@ -988,7 +1055,7 @@ void Watchy::updateFWBegin() { display.println(" "); display.println("Waiting for"); display.println("connection..."); - display.display(false); // full refresh + display.display(true); // full refresh BLE BT; BT.begin("Watchy BLE OTA"); @@ -1008,7 +1075,7 @@ void Watchy::updateFWBegin() { display.println(" "); display.println("Waiting for"); display.println("upload..."); - display.display(false); // full refresh + display.display(true); // full refresh } if (currentStatus == 1) { display.setFullWindow(); @@ -1033,7 +1100,7 @@ void Watchy::updateFWBegin() { display.println("completed!"); display.println(" "); display.println("Rebooting..."); - display.display(false); // full refresh + display.display(true); // full refresh delay(2000); esp_restart(); @@ -1047,19 +1114,23 @@ void Watchy::updateFWBegin() { display.println("BLE Disconnected!"); display.println(" "); display.println("exiting..."); - display.display(false); // full refresh + display.display(true); // full refresh delay(1000); break; } + prevStatus = currentStatus; } + + if(digitalRead(BACK_BTN_PIN) == ACTIVE_LOW) break; + delay(100); } // turn off radios WiFi.mode(WIFI_OFF); btStop(); - showMenu(menuIndex, false); + showMenu(menuIndex, true); } void Watchy::showSyncNTP() { @@ -1071,7 +1142,7 @@ void Watchy::showSyncNTP() { display.println("Syncing NTP... "); display.print("GMT offset: "); display.println(gmtOffset); - display.display(false); // full refresh + display.display(true); // full refresh if (connectWiFi()) { if (syncNTP()) { display.println("NTP Sync Success\n"); @@ -1103,7 +1174,7 @@ void Watchy::showSyncNTP() { } display.display(true); // full refresh delay(3000); - showMenu(menuIndex, false); + showMenu(menuIndex, true); } bool Watchy::syncNTP() { // NTP sync - call after connecting to WiFi and @@ -1121,6 +1192,7 @@ bool Watchy::syncNTP(long gmt, String ntpServer) { // WiFi and remember to turn it back off WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, ntpServer.c_str(), gmt); + timeClient.setTimeOffset(gmt); timeClient.begin(); if (!timeClient.forceUpdate()) { return false; // NTP sync failed diff --git a/src/Watchy.h b/src/Watchy.h index b7c7a89..4344eec 100644 --- a/src/Watchy.h +++ b/src/Watchy.h @@ -16,6 +16,7 @@ #include "bma.h" #include "config.h" #include "esp_chip_info.h" +#include "TimezonesGMT.h" #ifdef ARDUINO_ESP32S3_DEV #include "Watchy32KRTC.h" #include "soc/rtc.h" @@ -27,6 +28,8 @@ #include "soc/rtc_cntl_reg.h" #include "time.h" #include "esp_sntp.h" + #include "hal/rtc_io_types.h" + #include "driver/rtc_io.h" #define uS_TO_S_FACTOR 1000000ULL //Conversion factor for micro seconds to seconds #define ADC_VOLTAGE_DIVIDER ((360.0f+100.0f)/360.0f) //Voltage divider at battery ADC #else @@ -116,5 +119,6 @@ extern RTC_DATA_ATTR int menuIndex; extern RTC_DATA_ATTR BMA423 sensor; extern RTC_DATA_ATTR bool WIFI_CONFIGURED; extern RTC_DATA_ATTR bool BLE_CONFIGURED; +extern RTC_DATA_ATTR bool USB_PLUGGED_IN; #endif diff --git a/src/Watchy32KRTC.cpp b/src/Watchy32KRTC.cpp index 02555b1..9b9adb8 100644 --- a/src/Watchy32KRTC.cpp +++ b/src/Watchy32KRTC.cpp @@ -1,17 +1,19 @@ #include "Watchy32KRTC.h" +#include "TimezonesGMT.h" Watchy32KRTC::Watchy32KRTC(){} void Watchy32KRTC::init() { + if(TIMEZONES_NON_GMT_OVERRIDE == 0){ + setenv("TZ", timeZones[TIMEZONES_SELECTED].timezone, 1); + } else if (TIMEZONES_NON_GMT_OVERRIDE == 1) { + setenv("TZ", tz_override.timezone, 1); + } else { + setenv("TZ", "GMT0", 1); + } -} - -/* - - setenv("TZ", "", 1); tzset(); - -*/ +} void Watchy32KRTC::config(String datetime) { // String datetime format is YYYY:MM:DD:HH:MM:SS struct tm timeInfo; diff --git a/src/config.h b/src/config.h index 426bed1..e69968e 100644 --- a/src/config.h +++ b/src/config.h @@ -2,7 +2,7 @@ #define CONFIG_H // Versioning -#define WATCHY_LIB_VER "1.4.13" +#define WATCHY_LIB_VER "1.4.14" //pins @@ -104,9 +104,11 @@ // set time #define SET_HOUR 0 #define SET_MINUTE 1 -#define SET_YEAR 2 -#define SET_MONTH 3 -#define SET_DAY 4 +#define SET_TZ 2 +#define SET_YEAR 3 +#define SET_MONTH 4 +#define SET_DAY 5 + #define HOUR_12_24 24 // BLE OTA #define BLE_DEVICE_NAME "Watchy BLE OTA"