Black Lives Matter - Action and Equality. ... Adafruit is open and shipping.
0

sunrise and sunset for a fixed location
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

sunrise and sunset for a fixed location

by Steve_3000 on Thu Jun 04, 2020 12:07 am

I have a Feather M4 Express with CP 5.3. Sitting on top of it is a DS3231 Precision RTC FeatherWing, product ID 3028.[1]

Is there a way CircuitPython can determine the time of sunrise and sunset in my particular fixed location on each day? I do not need it to determine my location. I can hard code my latitude and longitude. I do not need or want a gps Wing or gps breakout for this project.

As a start, I would like the red LED to go on at sunrise and go off at sunset. Eventually I will want to control an external device but that can wait till I can get my code working. Is there some library somewhere that I can import to the Feather M4 Express and plug the date, latitude, and longitude, into a function and get the sunrise and sunset time for that day? I do not even need it to tell me whether or not it is daylight savings, because there is no user facing display of the time.

Thank you.

[1]I have copied code from Welcome to CP, CP Essentials, and here: https://learn.adafruit.com/adafruit-ds3 ... cuitpython. I can set the RTC, read its data, seconds, minutes, hours, month, day etc. I can get it to light the red LED certain times of the day.

Steve_3000
 
Posts: 28
Joined: Wed Oct 10, 2018 2:39 pm

Re: sunrise and sunset for a fixed location

by adafruit_support_bill on Thu Jun 04, 2020 5:29 am

If you search the web there are lots of resources out there.

There is an algorithm for that published here:
https://www.edwilliams.org/sunrise_sunset_algorithm.htm

And a python implementation here:
https://steemit.com/steemstem/@procrast ... ing-python

adafruit_support_bill
 
Posts: 77937
Joined: Sat Feb 07, 2009 10:11 am

Re: sunrise and sunset for a fixed location

by Steve_3000 on Sun Jun 07, 2020 12:34 pm

Thank you for your reply. The Python implementation you link to is something I can perhaps one day aspire to implement and later, possibly even understand. :-) It is certainly more straightforward and more to the point than what I was able to find in my internet searches.

Or perhaps someday it will be rendered as a library so I can just plug in longitude and latitude and get what I need like how it is currently possible to do:
import time
...
current = ds3231.datetime

In the meanwhile, I realized that I only needed very rough estimates of sunrise and sunset, so I looked them up for my location for the first day of each month. And further I realized that because there is no time display on my project I do not need to calculate daylight savings dates. So I did something that is currently within my ability. And It Is Working!.

I quote a sample of my code for its possible amusement value. (Starting variable names with a "v" is something I got used to doing when I was scripting a database program in the mid 1990s):
Code: Select all | TOGGLE FULL SIZE
    if vmon == 1:
        vsunrise = 60*7+17
       vsunset = 60*17+34
    if vmon == 2:
        vsunrise = 60*7+10
        vsunset = 60*17+59
    if vmon == 3:
        vsunrise = 60*6+45
        vsunset = 60*18+21
    # etc

Steve_3000
 
Posts: 28
Joined: Wed Oct 10, 2018 2:39 pm

Re: sunrise and sunset for a fixed location

by Steve_3000 on Tue Jun 09, 2020 7:27 pm

While waiting for some parts to arrive I went back to the link you posted:
https://steemit.com/steemstem/@procrastilearner/killing-time-with-recreational-math-calculate-sunrise-and-sunset-times-using-python
I used the mu Check feature to clean it up, and also delete a bunch of commented out sample city examples. Added "import board" just in case, then saved it to a Feather M4 Express running CP 5.3.0.
The code fails before it even get a chance to start, as follows
"Traceback (most recent call last):
File "code.py", line 11, in <module>
ImportError: no module named 'datetime'"
Is there a datetime module, referenced in line 11, available for CircuitPython 5.3?
Thank you.
The code is:
Code: Select all | TOGGLE FULL SIZE
# Write your code here :-)
# **************************************************************************
# This code is released by Procrastilearner under the CC BY-SA 4.0 license.
#
# Source for the sunrise calculation:
#     https://en.wikipedia.org/wiki/Sunrise_equation
# **************************************************************************
import time
import board
import math
import datetime

# *****************************************
# Some sample locations
# Toronto Ontario Canada
latitude_deg = 43.65
longitude_deg = -79.38
timezone = -4.0
# Daylight Savings Time is in effect, this would be -5 for winter time

def date_to_jd(year, month, day):
    # Convert a date to Julian Day.
    # Algorithm from 'Practical Astronomy with your Calculator or Spreadsheet',
    # 4th ed., Duffet-Smith and Zwart, 2011.
    # This function extracted from https://gist.github.com/jiffyclub/1294443
    if month == 1 or month == 2:
        yearp = year - 1
        monthp = month + 12
    else:
        yearp = year
        monthp = month
    # this checks where we are in relation to October 15, 1582, the beginning
    # of the Gregorian calendar.
    if ((year < 1582) or
            (year == 1582 and month < 10) or
            (year == 1582 and month == 10 and day < 15)):
        # before start of Gregorian calendar
        B = 0
    else:
        # after start of Gregorian calendar
        A = math.trunc(yearp / 100.)
        B = 2 - A + math.trunc(A / 4.)

    if yearp < 0:
        C = math.trunc((365.25 * yearp) - 0.75)
    else:
        C = math.trunc(365.25 * yearp)
    D = math.trunc(30.6001 * (monthp + 1))
    jd = B + C + D + day + 1720994.5
    return jd
# end of date_to_jd

pi = 3.14159265359

latitude_radians = math.radians(latitude_deg)
longitude__radians = math.radians(longitude_deg)

jd2000 = 2451545  # the julian date for Jan 1 2000 at noon

currentDT = datetime.datetime.now()
current_year = currentDT.year
current_month = currentDT.month
current_day = currentDT.day
current_hour = currentDT.hour

jd_now = date_to_jd(current_year, current_month, current_day)

n = jd_now - jd2000 + 0.0008

jstar = n - longitude_deg/360

M_deg = (357.5291 + 0.98560028 * jstar) % 360
M = M_deg * pi/180

C = 1.9148 * math.sin(M) + 0.0200 * math.sin(2*M) + 0.0003 * math.sin(3*M)

lamda_deg = math.fmod(M_deg + C + 180 + 102.9372, 360)

lamda = lamda_deg * pi/180

Jtransit = 2451545.5 + jstar + 0.0053 * math.sin(M) - 0.0069 * math.sin(2*lamda)

earth_tilt_deg = 23.44
earth_tilt_rad = math.radians(earth_tilt_deg)

sin_delta = math.sin(lamda) * math.sin(earth_tilt_rad)
angle_delta = math.asin(sin_delta)

sun_disc_deg = -0.83
sun_disc_rad = math.radians(sun_disc_deg)

cos_omega = (math.sin(sun_disc_rad) - math.sin(latitude_radians) * math.sin(angle_delta))/(math.cos(latitude_radians) * math.cos(angle_delta))

omega_radians = math.acos(cos_omega)
omega_degrees = math.degrees(omega_radians)

# Output section
print("------------------------------")
print("Today's date is " + currentDT.strftime("%Y-%m-%d"))
print("------------------------------")
# ("%Y-%m-%d %H:%M")

print("Latitude =  " + str(latitude_deg))
print("Longitude = " + str(longitude_deg))
print("Timezone =  " + str(timezone))
print("------------------------------")

Jrise = Jtransit - omega_degrees/360
numdays = Jrise - jd2000
numdays = numdays + 0.5  # offset because Julian dates start at noon
numdays = numdays + timezone/24  # offset for time zone
sunrise = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
print("Sunrise is at " + sunrise.strftime("%H:%M"))

Jset = Jtransit + omega_degrees/360
numdays = Jset - jd2000
numdays = numdays + 0.5  # offset because Julian dates start at noon
numdays = numdays + timezone/24  # offset for time zone
sunset = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
print("Sunset is at  " + sunset.strftime("%H:%M"))
print("------------------------------")

Steve_3000
 
Posts: 28
Joined: Wed Oct 10, 2018 2:39 pm

Re: sunrise and sunset for a fixed location

by adafruit_support_bill on Tue Jun 09, 2020 7:46 pm

Since you are using the DS3231, you will need to use the library we provide for it:
https://learn.adafruit.com/adafruit-ds3 ... cuitpython

adafruit_support_bill
 
Posts: 77937
Joined: Sat Feb 07, 2009 10:11 am

Re: sunrise and sunset for a fixed location

by Steve_3000 on Tue Jun 09, 2020 11:45 pm

I had the ds3231 lines in there but I deleted them before my last post. I put the lines back (as shown in the code below), but the same error occurs. Somehow the module "datetime" is still missing.
Traceback (most recent call last):
File "code.py", line 14, in <module>
ImportError: no module named 'datetime'

Items in the lib folder include
adafruit_bus_device (a folder)
adafruit_featherwing (a folder)
adafruit_register (a folder)
adafruit_ds3231.mpy (a file)
What am I missing?
Code: Select all | TOGGLE FULL SIZE
# CircuitPython IO demo #1 - General Purpose I/O
# Write your code here :-)
# **************************************************************************
# This code is released by Procrastilearner under the CC BY-SA 4.0 license.
#
# Source for the sunrise calculation:
#     https://en.wikipedia.org/wiki/Sunrise_equation
# **************************************************************************
import time
import math
import board
import busio
import adafruit_ds3231
import datetime
from digitalio import DigitalInOut, Direction, Pull
i2c = busio.I2C(board.SCL, board.SDA)
ds3231 = adafruit_ds3231.DS3231(i2c)
# *****************************************
# Some sample locations
# Toronto Ontario Canada
latitude_deg = 43.65
longitude_deg = -79.38
timezone = -4.0
# Daylight Savings Time is in effect, this would be -5 for winter time

def date_to_jd(year, month, day):
    # Convert a date to Julian Day.
    # Algorithm from 'Practical Astronomy with your Calculator or Spreadsheet',
    # 4th ed., Duffet-Smith and Zwart, 2011.
    # This function extracted from https://gist.github.com/jiffyclub/1294443
    if month == 1 or month == 2:
        yearp = year - 1
        monthp = month + 12
    else:
        yearp = year
        monthp = month
    # this checks where we are in relation to October 15, 1582, the beginning
    # of the Gregorian calendar.
    if ((year < 1582) or
            (year == 1582 and month < 10) or
            (year == 1582 and month == 10 and day < 15)):
        # before start of Gregorian calendar
        B = 0
    else:
        # after start of Gregorian calendar
        A = math.trunc(yearp / 100.)
        B = 2 - A + math.trunc(A / 4.)

    if yearp < 0:
        C = math.trunc((365.25 * yearp) - 0.75)
    else:
        C = math.trunc(365.25 * yearp)
    D = math.trunc(30.6001 * (monthp + 1))
    jd = B + C + D + day + 1720994.5
    return jd
# end of date_to_jd

pi = 3.14159265359

latitude_radians = math.radians(latitude_deg)
longitude__radians = math.radians(longitude_deg)

jd2000 = 2451545  # the julian date for Jan 1 2000 at noon

currentDT = datetime.datetime.now()
current_year = currentDT.year
current_month = currentDT.month
current_day = currentDT.day
current_hour = currentDT.hour

jd_now = date_to_jd(current_year, current_month, current_day)

n = jd_now - jd2000 + 0.0008

jstar = n - longitude_deg/360

M_deg = (357.5291 + 0.98560028 * jstar) % 360
M = M_deg * pi/180

C = 1.9148 * math.sin(M) + 0.0200 * math.sin(2*M) + 0.0003 * math.sin(3*M)

lamda_deg = math.fmod(M_deg + C + 180 + 102.9372, 360)

lamda = lamda_deg * pi/180

Jtransit = 2451545.5 + jstar + 0.0053 * math.sin(M) - 0.0069 * math.sin(2*lamda)

earth_tilt_deg = 23.44
earth_tilt_rad = math.radians(earth_tilt_deg)

sin_delta = math.sin(lamda) * math.sin(earth_tilt_rad)
angle_delta = math.asin(sin_delta)

sun_disc_deg = -0.83
sun_disc_rad = math.radians(sun_disc_deg)

cos_omega = (math.sin(sun_disc_rad) - math.sin(latitude_radians) * math.sin(angle_delta))/(math.cos(latitude_radians) * math.cos(angle_delta))

omega_radians = math.acos(cos_omega)
omega_degrees = math.degrees(omega_radians)

# Output section
print("------------------------------")
print("Today's date is " + currentDT.strftime("%Y-%m-%d"))
print("------------------------------")
# ("%Y-%m-%d %H:%M")

print("Latitude =  " + str(latitude_deg))
print("Longitude = " + str(longitude_deg))
print("Timezone =  " + str(timezone))
print("------------------------------")

Jrise = Jtransit - omega_degrees/360
numdays = Jrise - jd2000
numdays = numdays + 0.5  # offset because Julian dates start at noon
numdays = numdays + timezone/24  # offset for time zone
sunrise = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
print("Sunrise is at " + sunrise.strftime("%H:%M"))

Jset = Jtransit + omega_degrees/360
numdays = Jset - jd2000
numdays = numdays + 0.5  # offset because Julian dates start at noon
numdays = numdays + timezone/24  # offset for time zone
sunset = datetime.datetime(2000, 1, 1) + datetime.timedelta(numdays)
print("Sunset is at  " + sunset.strftime("%H:%M"))
print("------------------------------")

Steve_3000
 
Posts: 28
Joined: Wed Oct 10, 2018 2:39 pm

Re: sunrise and sunset for a fixed location

by adafruit_support_bill on Wed Jun 10, 2020 5:29 am

The adafruit_ds3231 library is your source of date and time. You don't need to import a second datetime module.

adafruit_support_bill
 
Posts: 77937
Joined: Sat Feb 07, 2009 10:11 am

Please be positive and constructive with your questions and comments.