link> Forum Thread
This script uses the latest Lua integer based trig functions to calculate sunrise and sunset times. The user selects a city name and either the current date or a date picked from the parameter menu. To use this script, copy the geo_data.txt file listed below to your SD card in the "A/CHDK/DATA/" directory and the script itself to SD card in the "A/CHDK/SCRIPTS" directory. You may want to edit the geo_date.txt file to include additional cities and locations.
twilight.lua[]
--[[
********************************
Licence: GPL
(c) 2012 msl
thx rudi for cordic & script check
v0.3
********************************
@title Twilight
@param a Current Date?
@default a 1
@range a 0 1
@param y Year
@default y 0
@values y 2012 2013 2014 2015 2016 2017 2018 2019 2020
@param m Month
@default m 0
@values m Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dez
@param d Day
@default d 30
@range d 1 31
@param s Daylight Saving Time?
@default s 0
@range s 0 1
]]
--FUNCTIONS------------------------------
-- Split string and write in array -> string.split(string,delimiter)
function string:split(delimiter)
local result = { }
local from = 1
local delim_from, delim_to = string.find(self, delimiter, from )
while delim_from do
table.insert( result, string.sub(self, from , delim_from-1 ) )
from = delim_to + 1
delim_from, delim_to = string.find(self, delimiter, from )
end
table.insert( result, string.sub(self, from ) )
return result
end
-- remove leading & trailing spaces -> string.trim(string)
function string:trim()
return (string.gsub(self, "^%s*(.-)%s*$", "%1"))
end
function load_data(dfile)
if os.stat(dfile) then
local file = io.open(dfile)
local line_id = 0
for line in file:lines(dfile) do
if string.find(line, "#") == nil then
local array = string.split(line,";")
if table.getn(array) > 3 then
array[2] = tonumber(array[2])
array[3] = tonumber(array[3])
array[4] = tonumber(array[4])
if (type(array[1]) == "string") then
array[1] = string.trim(array[1])
if (type(array[2]) == "number") and (array[2] <= 1800 or array[2] >= -1800) then
if (type(array[3]) == "number") and (array[3] <= 1800 or array[3] >= -1800) then
if (type(array[4]) == "number") and (array[4] <= 12 or array[4] >= -12) then
line_id = line_id + 1
location[line_id] = {}
location[line_id].name = array[1]
location[line_id].lat = array[2]
location[line_id].lng = array[3]
location[line_id].utc = array[4]
end
end
end
end
end
end
end
file:close()
return true, line_id
else
return false
end
end
function call_data()
--data_file = "A/CHDK/DATA/geo_data.txt"
cls()
print("File browser will open.")
print("Choose a file.")
console_redraw()
sleep(2000)
cls()
data_file = file_browser("A/CHDK/DATA")
if data_file ~= nil then
data, count = load_data(data_file)
else
data = false
end
if data == false then
print("Could not load external data!")
else
print(count, "records are read.")
end
console_redraw()
sleep(2000)
end
function is_leap_year(year)
return year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0)
end
function get_day_of_year(year, month, day)
local day_of_year = 0
local feb = 28
if is_leap_year(year) then feb = 29 end
local days_in_month = {31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
for i = 1, month-1 do
day_of_year=day_of_year + days_in_month[i]
end
return day_of_year + day
end
function sun_times(doy, h, lat, lng, utc)
--based on http://lexikon.astronomie.info/zeitgleichung/
--declination = 0.4095*sin(0.016906*(T-80.086))
local D = imath.muldiv(imath.sinr(imath.muldiv(16906, doy*1000-80086,1000000)), 4095, 10000)
--time equation: WOZ - MOZ = -0.171*sin(0.0337 * T + 0.465) - 0.1299*sin(0.01787 * T - 0.168)
local WOZ = imath.mul(imath.sinr(((337 * doy) + (465*10))/10), -171)
local MOZ = imath.mul(imath.sinr(((1787 * doy) - (168*100))/100), 130)
local time_equation = WOZ - MOZ
--timediff = 12*arccos((sin(h) - sin(B)*sin(declination)) / (cos(B)*cos(declination)))/Pi
local time_diff = 12 * imath.scale * imath.acosr(imath.div((imath.sind(h) - imath.mul(imath.sind(lat), imath.sinr(D))), imath.mul(imath.cosd(lat), imath.cosr(D)))) / imath.pi
--suntop = 12 + timezone - longitude /15 - time equation
local top = (12 + utc) * imath.scale - imath.div(lng * 100, 15 * imath.scale) - time_equation
local rising = top - time_diff
local setting = top + time_diff
return rising, setting, top
end
function restore()
cls()
set_console_layout(0,0,25,5)
set_console_autoredraw(1)
end
--MAIN-----------------------
--date
year = 2012 + y
if a ==1 then year = os.date("%Y") end
month = m + 1
if a ==1 then month = os.date("%m") end
day = d
if month == 2 and day > 28 then
if is_leap_year(year) then
day = 29
else
day = 28
end
end
if a ==1 then day = os.date("%d") end
--data
h1=-833 --sunset/sunrise h=-50'
h2=-6000 --civil twilight h= -6°
location = {}
location[1] = {}
location[1].name = "Berlin" -- location
location[1].lat = 525 -- latitude 52.5°
location[1].lng = 135 -- longitude 13.5°
location[1].utc = 1 -- time zone +1 h
--user interface
cls()
set_console_layout(5,3,40,14)
set_console_autoredraw(0)
line = "-----------------------------------"
location_id = 1
DoY=get_day_of_year(year, month, day)
while true do
location_id_max = table.getn(location)
Utc = location[location_id].utc + s
Utc_str = "UTC +"
if Utc == 0 then Utc_str = "UTC +/-" end
if Utc < 0 then Utc_str = "UTC " end
Lat = location[location_id].lat
Lat_str = string.format("%d.%d°", Lat/10, math.abs(Lat%10))
Lat_deg = Lat*100
Lng = location[location_id].lng
Lng_str = string.format("%d.%d°", Lng/10, math.abs(Lng%10))
sunrise, sunset, suntop = sun_times(DoY, h1, Lat_deg, Lng, Utc)
dawn, dusk = sun_times(DoY, h2, Lat_deg, Lng, Utc)
cls()
print(string.format(" [\18] %s %s%d", location[location_id].name, Utc_str, location[location_id].utc))
print(string.format(" %s %s %02d.%02d.%4d", Lat_str, Lng_str, day, month, year))
print(line)
print(string.format(" civil dawn: %02d:%02d clock",dawn/1000, dawn%1000*600/100/100))
print(string.format(" sunrise: %02d:%02d clock",sunrise/1000, sunrise%1000*600/100/100))
print(string.format(" sun top: %02d:%02d clock",suntop/1000, suntop%1000*600/100/100))
print(string.format(" sunset: %02d:%02d clock",sunset/1000, sunset%1000*600/100/100))
print(string.format(" civil dusk: %02d:%02d clock",dusk/1000, dusk%1000*600/100/100))
print(line)
print(" [SET] load geo data [MENU] end")
console_redraw()
wait_click(0)
if is_pressed("down") then
location_id = location_id + 1
if location_id > location_id_max then location_id = 1 end
elseif is_pressed("up") then
location_id = location_id - 1
if location_id < 1 then location_id = location_id_max end
elseif is_pressed("set") then call_data()
elseif is_pressed("menu") then break
end
end
restore()
geo_data.txt[]
####################################################################### #location;latitude xxx.x°=xxxx;longitude xxx.x°=xxxx;local time +/-UTC# ####################################################################### Berlin;525;135;1 Kiel;543;101;1 Rostock;540;121;1 Schwerin;536;113;1 Lübeck;535;104;1 Hamburg;533;100;1 Bremen;530;88;1 Hannover;523;97;1 Magdeburg;521;116;1 Leipzig;513;123;1 Dresden;510;137;1 Köln;509;69;1 Koblenz;503;76;1 Mainz;500;82;1 Frankfurt;501;86;1 Nürnberg;494;110;1 Saarbrücken;492;70;1 Regensburg;490;121;1 Stuttgart;487;91;1 Freiburg;479;78;1 München;481;115;1 # London;513;0;0 Wien;482;163;1 Prag;500;144;1 Warschau;522;210;1 Maribor;465;156;1 Zagreb;458;159;1 Bern;469;74;1 Paris;488;23;1 Luxemburg;498;61;1 Brüssel;508;43;1 Amsterdam;523;48;1 Kopenhagen;556;125;1 Rom;419;124;1 Madrid;404;-37;1 Oslo;599;107;1 Stockholm;593;180;1 Helsinki;601;249;2 Lahti;609;256;2 Las Palmas;281;-154;0 Rio de Janeiro;-229;-432;-3 Sydney;-338;1512;10 New York;407;-740;-5 Tokio;356;1396;9 Singapur;13;1038;7