mirror of https://github.com/sqfmi/Watchy.git
commit
2a2fb3e5c2
|
@ -0,0 +1,96 @@
|
||||||
|
// Calculate the phase and position of the moon for a given date.
|
||||||
|
// The algorithm is simple and adequate for many purposes.
|
||||||
|
//
|
||||||
|
// This software was originally adapted to javascript by Stephen R. Schmitt
|
||||||
|
// from a BASIC program from the 'Astronomical Computing' column of Sky & Telescope,
|
||||||
|
// April 1994, page 86, written by Bradley E. Schaefer.
|
||||||
|
//
|
||||||
|
// Subsequently adapted from Stephen R. Schmitt's javascript to c++ for the Arduino
|
||||||
|
// by Cyrus Rahman, this work is subject to Stephen Schmitt's copyright:
|
||||||
|
//
|
||||||
|
// Copyright 2004 Stephen R. Schmitt
|
||||||
|
// You may use or modify this source code in any way you find useful, provided
|
||||||
|
// that you agree that the author(s) have no warranty, obligations or liability. You
|
||||||
|
// must determine the suitability of this source code for your use.
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "MoonPhase.h"
|
||||||
|
|
||||||
|
// Names of lunar phases
|
||||||
|
static const char *phaseNames[] = {"New", "Evening Crescent", "First Quarter",
|
||||||
|
"Waxing Gibbous", "Full", "Waning Gibbous",
|
||||||
|
"Last Quarter", "Morning Crescent"};
|
||||||
|
// Names of Zodiac constellations
|
||||||
|
static const char *zodiacNames[] = {"Pisces", "Aries", "Taurus", "Gemini", "Cancer",
|
||||||
|
"Leo", "Virgo", "Libra", "Scorpio", "Sagittarius",
|
||||||
|
"Capricorn", "Aquarius"};
|
||||||
|
// Ecliptic angles of Zodiac constellations
|
||||||
|
static const float zodiacAngles[] = {33.18, 51.16, 93.44, 119.48, 135.30, 173.34,
|
||||||
|
224.17, 242.57, 271.26, 302.49, 311.72, 348.58};
|
||||||
|
|
||||||
|
// Constructor initialization.
|
||||||
|
MoonPhase::MoonPhase() {
|
||||||
|
jDate = 0;
|
||||||
|
phase = 0;
|
||||||
|
age = 0;
|
||||||
|
fraction = 0;
|
||||||
|
distance = 0;
|
||||||
|
latitude = 0;
|
||||||
|
longitude = 0;
|
||||||
|
phaseName = zodiacName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the Moon Phase and orbital positions for the specified time.
|
||||||
|
void
|
||||||
|
MoonPhase::calculate(time_t t) {
|
||||||
|
jDate = julianDate(t);
|
||||||
|
|
||||||
|
// Calculate illumination (synodic) phase.
|
||||||
|
// From number of days since new moon on Julian date MOON_SYNODIC_OFFSET
|
||||||
|
// (1815UTC January 6, 2000), determine remainder of incomplete cycle.
|
||||||
|
phase = (jDate - MOON_SYNODIC_OFFSET) / MOON_SYNODIC_PERIOD;
|
||||||
|
phase -= floor(phase);
|
||||||
|
|
||||||
|
// Calculate age and illumination fraction.
|
||||||
|
age = phase * MOON_SYNODIC_PERIOD;
|
||||||
|
fraction = (1.0 - cos(2 * M_PI * phase)) * 0.5;
|
||||||
|
phaseName = phaseNames[(int)(phase * 8 + 0.5) % 8];
|
||||||
|
|
||||||
|
// Calculate distance from anomalistic phase.
|
||||||
|
double distancePhase = (jDate - MOON_DISTANCE_OFFSET) / MOON_DISTANCE_PERIOD;
|
||||||
|
distancePhase -= floor(distancePhase);
|
||||||
|
distance = 60.4 - 3.3 * cos(2 * M_PI * distancePhase)
|
||||||
|
- 0.6 * cos(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase)
|
||||||
|
- 0.5 * cos(2 * 2 * M_PI * phase);
|
||||||
|
|
||||||
|
// Calculate ecliptic latitude from nodal (draconic) phase.
|
||||||
|
double latPhase = (jDate - MOON_LATITUDE_OFFSET) / MOON_LATITUDE_PERIOD;
|
||||||
|
latPhase -= floor(latPhase);
|
||||||
|
latitude = 5.1 * sin(2 * M_PI * latPhase);
|
||||||
|
|
||||||
|
// Calculate ecliptic longitude from sidereal motion.
|
||||||
|
double longPhase = (jDate - MOON_LONGITUDE_OFFSET) / MOON_LONGITUDE_PERIOD;
|
||||||
|
longPhase -= floor(longPhase);
|
||||||
|
longitude = 360 * longPhase
|
||||||
|
+ 6.3 * sin(2 * M_PI * distancePhase)
|
||||||
|
+ 1.3 * sin(2 * 2 * M_PI * phase - 2 * M_PI * distancePhase)
|
||||||
|
+ 0.7 * sin(2 * 2 * M_PI * phase);
|
||||||
|
if (longitude > 360)
|
||||||
|
longitude -= 360;
|
||||||
|
|
||||||
|
// Select the Zodiac name.
|
||||||
|
zodiacName = zodiacNames[0];
|
||||||
|
for (int i = 0; i < sizeof(zodiacAngles) / sizeof(float); i++) {
|
||||||
|
if (longitude < zodiacAngles[i]) {
|
||||||
|
zodiacName = zodiacNames[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine Julian date from Unix time.
|
||||||
|
// Provides marginally accurate results with older Arduino 4-byte double.
|
||||||
|
double
|
||||||
|
MoonPhase::julianDate(time_t t) {
|
||||||
|
return (t / 86400.0L + 2440587.5);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef MoonPhase_h
|
||||||
|
#define MoonPhase_h
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define MOON_SYNODIC_PERIOD 29.530588853 // Period of moon cycle in days.
|
||||||
|
#define MOON_SYNODIC_OFFSET 2451550.26 // Reference cycle offset in days.
|
||||||
|
#define MOON_DISTANCE_PERIOD 27.55454988 // Period of distance oscillation
|
||||||
|
#define MOON_DISTANCE_OFFSET 2451562.2
|
||||||
|
#define MOON_LATITUDE_PERIOD 27.212220817 // Latitude oscillation
|
||||||
|
#define MOON_LATITUDE_OFFSET 2451565.2
|
||||||
|
#define MOON_LONGITUDE_PERIOD 27.321582241 // Longitude oscillation
|
||||||
|
#define MOON_LONGITUDE_OFFSET 2451555.8
|
||||||
|
|
||||||
|
class MoonPhase {
|
||||||
|
public:
|
||||||
|
double jDate;
|
||||||
|
double phase; // 0 - 1, 0.5 = full
|
||||||
|
double age; // Age in days of current cycle
|
||||||
|
double fraction; // Fraction of illuminated disk
|
||||||
|
double distance; // Moon distance in earth radii
|
||||||
|
double latitude; // Moon ecliptic latitude
|
||||||
|
double longitude; // Moon ecliptic longitude
|
||||||
|
const char *phaseName; // New, Full, etc.
|
||||||
|
const char *zodiacName; // Constellation
|
||||||
|
|
||||||
|
MoonPhase();
|
||||||
|
void calculate(time_t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
double julianDate(time_t);
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -27,6 +27,7 @@ RTC_DATA_ATTR bool USB_PLUGGED_IN = false;
|
||||||
RTC_DATA_ATTR tmElements_t bootTime;
|
RTC_DATA_ATTR tmElements_t bootTime;
|
||||||
RTC_DATA_ATTR uint32_t lastIPAddress;
|
RTC_DATA_ATTR uint32_t lastIPAddress;
|
||||||
RTC_DATA_ATTR char lastSSID[30];
|
RTC_DATA_ATTR char lastSSID[30];
|
||||||
|
RTC_DATA_ATTR MoonPhase mp;
|
||||||
|
|
||||||
void Watchy::init(String datetime) {
|
void Watchy::init(String datetime) {
|
||||||
esp_sleep_wakeup_cause_t wakeup_reason;
|
esp_sleep_wakeup_cause_t wakeup_reason;
|
||||||
|
@ -39,7 +40,7 @@ void Watchy::init(String datetime) {
|
||||||
RTC.init();
|
RTC.init();
|
||||||
// Init the display since is almost sure we will use it
|
// Init the display since is almost sure we will use it
|
||||||
display.epd2.initWatchy();
|
display.epd2.initWatchy();
|
||||||
|
mp = MoonPhase();
|
||||||
switch (wakeup_reason) {
|
switch (wakeup_reason) {
|
||||||
#ifdef ARDUINO_ESP32S3_DEV
|
#ifdef ARDUINO_ESP32S3_DEV
|
||||||
case ESP_SLEEP_WAKEUP_TIMER: // RTC Alarm
|
case ESP_SLEEP_WAKEUP_TIMER: // RTC Alarm
|
||||||
|
@ -97,6 +98,9 @@ void Watchy::init(String datetime) {
|
||||||
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
|
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t epoch = makeTime(currentTime);
|
||||||
|
mp.calculate(epoch);
|
||||||
deepSleep();
|
deepSleep();
|
||||||
}
|
}
|
||||||
void Watchy::deepSleep() {
|
void Watchy::deepSleep() {
|
||||||
|
@ -167,6 +171,8 @@ void Watchy::handleButtonPress() {
|
||||||
case 6:
|
case 6:
|
||||||
showSyncNTP();
|
showSyncNTP();
|
||||||
break;
|
break;
|
||||||
|
case 7:
|
||||||
|
showMoonPhase();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -249,6 +255,8 @@ void Watchy::handleButtonPress() {
|
||||||
case 6:
|
case 6:
|
||||||
showSyncNTP();
|
showSyncNTP();
|
||||||
break;
|
break;
|
||||||
|
case 7:
|
||||||
|
showMoonPhase();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -302,9 +310,9 @@ void Watchy::showMenu(byte menuIndex, bool partialRefresh) {
|
||||||
const char *menuItems[] = {
|
const char *menuItems[] = {
|
||||||
"About Watchy", "Vibrate Motor", "Show Accelerometer",
|
"About Watchy", "Vibrate Motor", "Show Accelerometer",
|
||||||
"Set Time", "Setup WiFi", "Update Firmware",
|
"Set Time", "Setup WiFi", "Update Firmware",
|
||||||
"Sync NTP"};
|
"Sync NTP", "Moon Phase"};
|
||||||
for (int i = 0; i < MENU_LENGTH; i++) {
|
for (int i = 0; i < MENU_LENGTH; i++) {
|
||||||
yPos = MENU_HEIGHT + (MENU_HEIGHT * i);
|
yPos = MENU_HEIGHT/2 + (MENU_HEIGHT * i);
|
||||||
display.setCursor(0, yPos);
|
display.setCursor(0, yPos);
|
||||||
if (i == menuIndex) {
|
if (i == menuIndex) {
|
||||||
display.getTextBounds(menuItems[i], 0, yPos, &x1, &y1, &w, &h);
|
display.getTextBounds(menuItems[i], 0, yPos, &x1, &y1, &w, &h);
|
||||||
|
@ -335,9 +343,9 @@ void Watchy::showFastMenu(byte menuIndex) {
|
||||||
const char *menuItems[] = {
|
const char *menuItems[] = {
|
||||||
"About Watchy", "Vibrate Motor", "Show Accelerometer",
|
"About Watchy", "Vibrate Motor", "Show Accelerometer",
|
||||||
"Set Time", "Setup WiFi", "Update Firmware",
|
"Set Time", "Setup WiFi", "Update Firmware",
|
||||||
"Sync NTP"};
|
"Sync NTP", "Moon Phase"};
|
||||||
for (int i = 0; i < MENU_LENGTH; i++) {
|
for (int i = 0; i < MENU_LENGTH; i++) {
|
||||||
yPos = MENU_HEIGHT + (MENU_HEIGHT * i);
|
yPos = MENU_HEIGHT/2 + (MENU_HEIGHT * i);
|
||||||
display.setCursor(0, yPos);
|
display.setCursor(0, yPos);
|
||||||
if (i == menuIndex) {
|
if (i == menuIndex) {
|
||||||
display.getTextBounds(menuItems[i], 0, yPos, &x1, &y1, &w, &h);
|
display.getTextBounds(menuItems[i], 0, yPos, &x1, &y1, &w, &h);
|
||||||
|
@ -404,6 +412,57 @@ void Watchy::showAbout() {
|
||||||
guiState = APP_STATE;
|
guiState = APP_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Watchy::showMoonPhase() {
|
||||||
|
|
||||||
|
RTC.read(currentTime);
|
||||||
|
time_t epoch = makeTime(currentTime);
|
||||||
|
mp.calculate(epoch);
|
||||||
|
|
||||||
|
display.setFullWindow();
|
||||||
|
display.fillScreen(GxEPD_BLACK);
|
||||||
|
display.setFont(&FreeMonoBold9pt7b);
|
||||||
|
display.setTextColor(GxEPD_WHITE);
|
||||||
|
display.setCursor(0, 10);
|
||||||
|
|
||||||
|
display.setCursor(0, MENU_HEIGHT);
|
||||||
|
|
||||||
|
display.print("Date: ");
|
||||||
|
display.println(mp.jDate);
|
||||||
|
|
||||||
|
display.print("Phase: ");
|
||||||
|
display.println(mp.phase);
|
||||||
|
|
||||||
|
display.print("Age: ");
|
||||||
|
display.print(mp.age);
|
||||||
|
display.println(" days");
|
||||||
|
|
||||||
|
display.print("Visibility: ");
|
||||||
|
display.print(mp.fraction);
|
||||||
|
display.println("%");
|
||||||
|
|
||||||
|
display.print("Distance: ");
|
||||||
|
display.print(mp.distance);
|
||||||
|
display.println(" er");
|
||||||
|
|
||||||
|
display.print("Latitude: ");
|
||||||
|
display.print(mp.latitude);
|
||||||
|
display.println("°");
|
||||||
|
|
||||||
|
display.print("Longitude: ");
|
||||||
|
display.print(mp.longitude);
|
||||||
|
display.println("°");
|
||||||
|
|
||||||
|
display.print("Ph.: ");
|
||||||
|
display.println(mp.phaseName);
|
||||||
|
|
||||||
|
display.print("Zodiac: ");
|
||||||
|
display.println(mp.zodiacName);
|
||||||
|
|
||||||
|
display.display(true); // full refresh
|
||||||
|
|
||||||
|
guiState = APP_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
void Watchy::showBuzz() {
|
void Watchy::showBuzz() {
|
||||||
display.setFullWindow();
|
display.setFullWindow();
|
||||||
display.fillScreen(GxEPD_BLACK);
|
display.fillScreen(GxEPD_BLACK);
|
||||||
|
@ -443,7 +502,7 @@ void Watchy::setTime() {
|
||||||
int8_t hour = currentTime.Hour;
|
int8_t hour = currentTime.Hour;
|
||||||
int8_t day = currentTime.Day;
|
int8_t day = currentTime.Day;
|
||||||
int8_t month = currentTime.Month;
|
int8_t month = currentTime.Month;
|
||||||
int8_t year = currentTime.Year; //tmYearToY2k(currentTime.Year);
|
int8_t year = tmYearToY2k(currentTime.Year);
|
||||||
#endif
|
#endif
|
||||||
int8_t gmt = gmtOffset / 3600;
|
int8_t gmt = gmtOffset / 3600;
|
||||||
|
|
||||||
|
@ -580,7 +639,7 @@ void Watchy::setTime() {
|
||||||
if (setIndex == SET_YEAR) { // blink minute digits
|
if (setIndex == SET_YEAR) { // blink minute digits
|
||||||
display.setTextColor(blink ? GxEPD_WHITE : GxEPD_BLACK);
|
display.setTextColor(blink ? GxEPD_WHITE : GxEPD_BLACK);
|
||||||
}
|
}
|
||||||
display.print(year);
|
display.print(1970 + year);
|
||||||
|
|
||||||
display.setTextColor(GxEPD_WHITE);
|
display.setTextColor(GxEPD_WHITE);
|
||||||
display.print("/");
|
display.print("/");
|
||||||
|
@ -613,7 +672,7 @@ void Watchy::setTime() {
|
||||||
#ifdef ARDUINO_ESP32S3_DEV
|
#ifdef ARDUINO_ESP32S3_DEV
|
||||||
tm.Year = year;
|
tm.Year = year;
|
||||||
#else
|
#else
|
||||||
tm.Year = year; //y2kYearToTm(year);
|
tm.Year = y2kYearToTm(year);
|
||||||
#endif
|
#endif
|
||||||
tm.Hour = hour;
|
tm.Hour = hour;
|
||||||
tm.Minute = minute;
|
tm.Minute = minute;
|
||||||
|
@ -1200,5 +1259,9 @@ bool Watchy::syncNTP(long gmt, String ntpServer) {
|
||||||
tmElements_t tm;
|
tmElements_t tm;
|
||||||
breakTime((time_t)timeClient.getEpochTime(), tm);
|
breakTime((time_t)timeClient.getEpochTime(), tm);
|
||||||
RTC.set(tm);
|
RTC.set(tm);
|
||||||
|
//Update also moon calendar.
|
||||||
|
RTC.read(currentTime);
|
||||||
|
time_t epoch = makeTime(currentTime);
|
||||||
|
mp.calculate(epoch);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "esp_chip_info.h"
|
#include "esp_chip_info.h"
|
||||||
#include "TimezonesGMT.h"
|
#include "TimezonesGMT.h"
|
||||||
|
#include "MoonPhase.h"
|
||||||
#ifdef ARDUINO_ESP32S3_DEV
|
#ifdef ARDUINO_ESP32S3_DEV
|
||||||
#include "Watchy32KRTC.h"
|
#include "Watchy32KRTC.h"
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
|
@ -86,6 +87,7 @@ public:
|
||||||
void showMenu(byte menuIndex, bool partialRefresh);
|
void showMenu(byte menuIndex, bool partialRefresh);
|
||||||
void showFastMenu(byte menuIndex);
|
void showFastMenu(byte menuIndex);
|
||||||
void showAbout();
|
void showAbout();
|
||||||
|
void showMoonPhase();
|
||||||
void showBuzz();
|
void showBuzz();
|
||||||
void showAccelerometer();
|
void showAccelerometer();
|
||||||
void showUpdateFW();
|
void showUpdateFW();
|
||||||
|
|
|
@ -99,8 +99,8 @@
|
||||||
#define MAIN_MENU_STATE 0
|
#define MAIN_MENU_STATE 0
|
||||||
#define APP_STATE 1
|
#define APP_STATE 1
|
||||||
#define FW_UPDATE_STATE 2
|
#define FW_UPDATE_STATE 2
|
||||||
#define MENU_HEIGHT 25
|
#define MENU_HEIGHT 24
|
||||||
#define MENU_LENGTH 7
|
#define MENU_LENGTH 8
|
||||||
// set time
|
// set time
|
||||||
#define SET_HOUR 0
|
#define SET_HOUR 0
|
||||||
#define SET_MINUTE 1
|
#define SET_MINUTE 1
|
||||||
|
|
Loading…
Reference in New Issue