From 753b669fec51472ec2f2bfab0a3a90381dd8036f Mon Sep 17 00:00:00 2001
From: jpawlowski
Date: Wed, 19 Jun 2019 10:21:35 +0000
Subject: [PATCH] 95_Astro: release v2.0.0
git-svn-id: https://svn.fhem.de/fhem/trunk@19645 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 12 +
fhem/FHEM/95_Astro.pm | 2591 +++++++++++++++++++++++++++++++----------
fhem/MAINTAINER.txt | 2 +-
3 files changed, 2006 insertions(+), 599 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index 1984c26e3..8b86581b2 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,17 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - update: 95_Astro: v2.0.0
+ device attributes for language, timezone and locale settings
+ new set command "update"
+ new attribute recomputeAt
+ support for disable attribute
+ improved startup and readings update behaviour
+ different custom horizon for morning/evening twilight
+ unit and label support for text
+ regional settings for numeric values and time in text format
+ enhanced options for Astro_Get()
+ fix some typos
+ stability improvements
- feature: 73_GardenaSmartBridge: change package code
- feature: 73_AMADCommBridge: change package code
- feature: 42_AptToDate: change every package code
diff --git a/fhem/FHEM/95_Astro.pm b/fhem/FHEM/95_Astro.pm
index 0bed4d6a9..669c3d7e9 100644
--- a/fhem/FHEM/95_Astro.pm
+++ b/fhem/FHEM/95_Astro.pm
@@ -30,13 +30,19 @@
#
########################################################################################
-package main;
+package FHEM::Astro;
use strict;
use warnings;
use POSIX;
+use utf8;
+use Encode;
+use FHEM::Meta;
+use GPUtils qw(GP_Import);
use Math::Trig;
+use Time::HiRes qw(gettimeofday);
use Time::Local;
+use UConv;
#use Data::Dumper;
my $DEG = pi/180.0;
@@ -47,267 +53,728 @@ my $deltaT = 65; # Correction time in s
my %Astro;
my %Date;
-my $astroversion = 1.52;
+#-- These we may set on request
+my %sets = (
+ "update" => "noArg",
+);
#-- These we may get on request
my %gets = (
- "version" => "V",
- "json" => "J",
- "text" => "T"
+ "json" => undef,
+ "text" => undef,
+ "version" => "noArg",
);
-my $astro_tt;
+#-- These we may configure
+my %attrs = (
+ "altitude" => undef,
+ "disable" => "1,0",
+ "horizon" => undef,
+ "interval" => undef,
+ "language" => "EN,DE,ES,FR,IT,NL,PL",
+ "latitude" => undef,
+ "lc_numeric" => "en_EN.UTF-8,de_DE.UTF-8,es_ES.UTF-8,fr_FR.UTF-8,it_IT.UTF-8,nl_NL.UTF-8,pl_PL.UTF-8",
+ "lc_time" => "en_EN.UTF-8,de_DE.UTF-8,es_ES.UTF-8,fr_FR.UTF-8,it_IT.UTF-8,nl_NL.UTF-8,pl_PL.UTF-8",
+ "longitude" => undef,
+ "recomputeAt" => "multiple-strict,MoonRise,MoonSet,MoonTransit,NewDay,SunRise,SunSet,SunTransit,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning",
+ "timezone" => undef,
+);
+
+my $json;
+my $tt;
+
+#-- Export variables to other programs
+our %transtable = (
+ EN => {
+ "coord" => "Coordinates",
+ "position" => "Position",
+ "longitude" => "Longitude",
+ "latitude" => "Latitude",
+ "altitude" => "Height a.s.l.",
+ "lonecl" => "Ecliptical longitude",
+ "latecl" => "Ecliptical latitude",
+ "ra" => "Right ascension",
+ "dec" => "Declination",
+ "az" => "Azimuth",
+ "alt" => "Horizontal altitude",
+ "age" => "Age",
+ "rise" => "Rise",
+ "set" => "Set",
+ "transit" => "Transit",
+ "distance" => "Distance",
+ "diameter" => "Diameter",
+ "toobs" => "to observer",
+ "toce" => "to Earth center",
+ "progress" => "Progress",
+ "twilightcivil" => "Civil twilight",
+ "twilightnautic" => "Nautical twilight",
+ "twilightastro" => "Astronomical twilight",
+ "twilightcustom" => "Custom twilight",
+ "sign" => "Zodiac sign",
+ "dst" => "daylight saving time",
+ "nt" => "standard time",
+ "hoursofsunlight" => "Hours of sunlight",
+ "hoursofnight" => "Hours of night",
+ "hoursofvisibility" => "Visibility",
-my %astro_transtable_EN = (
- "overview" => "Summary",
- "name" => "Name",
- "time" => "Time",
- "action" => "Action",
- "type" => "Type",
- "description" => "Description",
- "profile" => "Profile",
- #--
- "coord" => "Coordinates",
- "position" => "Position",
- "longitude" => "Longitude",
- "latitude" => "Latitude",
- "altitude" => "Height above sea",
- "lonecl" => "Ecliptical longitude",
- "latecl" => "Ecliptical latitude",
- "ra" => "Right ascension",
- "dec" => "Declination",
- "az" => "Azimuth",
- "alt" => "Horizontal altitude",
- "age" => "Age",
- "rise" => "Rise",
- "set" => "Set",
- "transit" => "Transit",
- "distance" => "Distance",
- "diameter" => "Diameter",
- "toobs" => "to observer",
- "toce" => "to Earth center",
- "twilightcivil" => "Civil twilight",
- "twilightnautic" => "Nautical twilight",
- "twilightastro" => "Astronomical twilight",
- "twilightcustom" => "Custom twilight",
- "sign" => "Zodiac sign",
- "dst" => "daylight saving time",
- #--
- "today" => "Today",
- "tomorrow" => "Tomorrow",
- "weekday" => "Day of Week",
- "date" => "Date",
- "jdate" => "Julian date",
- "dayofyear" => "day of year",
- "days" => "days",
- "timezone" => "Time Zone",
- "lmst" => "Local Sidereal Time",
- #--
- "monday" => ["Monday","Mon"],
- "tuesday" => ["Tuesday","Tue"],
- "wednesday" => ["Wednesday","Wed"],
- "thursday" => ["Thursday","Thu"],
- "friday" => ["Friday","Fri"],
- "saturday" => ["Saturday","Sat"],
- "sunday" => ["Sunday","Sun"],
- #--
- "season" => "Season",
- "spring" => "Spring",
- "summer" => "Summer",
- "fall" => "Fall",
- "winter" => "Winter",
#--
- "aries" => "Ram",
- "taurus" => "Bull",
- "gemini" => "Twins",
- "cancer" => "Crab",
- "leo" => "Lion",
- "virgo" => "Maiden",
- "libra" => "Scales",
- "scorpio" => "Scorpion",
- "sagittarius" => "Archer",
- "capricorn" => "Goat",
- "aquarius" => "Water Bearer",
- "pisces" => "Fish",
- #--
- "sun" => "Sun",
- #--
- "moon" => "Moon",
- "phase" => "Phase",
- "newmoon" => "New Moon",
- "waxingcrescent" => "Waxing Crescent",
- "firstquarter" => "First Quarter",
- "waxingmoon" => "Waxing Moon",
- "fullmoon" => "Full Moon",
- "waningmoon" => "Waning Moon",
- "lastquarter" => "Last Quarter",
- "waningcrescent" => "Waning Crescent"
- );
-
- my %astro_transtable_DE = (
- "overview" => "Zusammenfassung",
- "name" => "Name",
- "time" => "Zeit",
- "action" => "Aktion",
- "type" => "Typ",
- "description" => "Beschreibung",
- "profile" => "Profil",
- #--
- "coord" => "Koordinaten",
- "position" => "Position",
- "longitude" => "Länge",
- "latitude" => "Breite",
- "altitude" => "Höhe ü.M.",
- "lonecl" => "Eklipt. Länge",
- "latecl" => "Eklipt. Breite",
- "ra" => "Rektaszension",
- "dec" => "Deklination",
- "az" => "Azimut",
- "alt" => "Horizontwinkel",
- "age" => "Alter",
- "phase" => "Phase",
- "rise" => "Aufgang",
- "set" => "Untergang",
- "transit" => "Kulmination",
- "distance" => "Entfernung",
- "diameter" => "Durchmesser",
- "toobs" => "z. Beobachter",
- "toce" => "z. Erdmittelpunkt",
- "twilightcivil" => "Bürgerliche Dämmerung",
- "twilightnautic" => "Nautische Dämmerung",
- "twilightastro" => "Astronomische Dämmerung",
- "twilightcustom" => "Konfigurierte Dämmerung",
- "sign" => "Tierkreiszeichen",
- "dst" => "Sommerzeit",
- #--
- "today" => "Heute",
- "tomorrow" => "Morgen",
- "weekday" => "Wochentag",
- "date" => "Datum",
- "jdate" => "Julianisches Datum",
- "dayofyear" => "Tag d. Jahres",
- "days" => "Tage",
- "timezone" => "Zeitzone",
- "lmst" => "Lokale Sternzeit",
- #--
- "monday" => ["Montag","Mo"],
- "tuesday" => ["Dienstag","Di"],
- "wednesday" => ["Mittwoch","Mi"],
- "thursday" => ["Donnerstag","Do"],
- "friday" => ["Freitag","Fr"],
- "saturday" => ["Samstag","Sa"],
- "sunday" => ["Sonntag","So"],
- #--
- "season" => "Jahreszeit",
- "spring" => "Frühling",
- "summer" => "Sommer",
- "fall" => "Herbst",
- "winter" => "Winter",
- #--
- "aries" => "Widder",
- "taurus" => "Stier",
- "gemini" => "Zwillinge",
- "cancer" => "Krebs",
- "leo" => "Löwe",
- "virgo" => "Jungfrau",
- "libra" => "Waage",
- "scorpio" => "Skorpion",
- "sagittarius" => "Schütze",
- "capricorn" => "Steinbock",
- "aquarius" => "Wassermann",
- "pisces" => "Fische",
- #--
- "sun" => "Sonne",
- #--
- "moon" => "Mond",
- "phase" => "Phase",
- "newmoon" => "Neumond",
- "waxingcrescent" => "Zunehmende Sichel",
- "firstquarter" => "Erstes Viertel",
- "waxingmoon" => "Zunehmender Mond",
- "fullmoon" => "Vollmond",
- "waningmoon" => "Abnehmender Mond",
- "lastquarter" => "Letztes Viertel",
- "waningcrescent" => "Abnehmende Sichel"
- );
-
-my @zodiac=("aries","taurus","gemini","cancer","leo","virgo",
+ "time" => "Time",
+ "date" => "Date",
+ "jdate" => "Julian date",
+ "dayofyear" => "day of year",
+ "days" => "days",
+ "timezone" => "Time Zone",
+ "lmst" => "Local Sidereal Time",
+
+ #--
+ "season" => "Astronomical Season",
+ "spring" => "Spring",
+ "summer" => "Summer",
+ "fall" => "Fall",
+ "winter" => "Winter",
+
+ #--
+ "aries" => "Ram",
+ "taurus" => "Bull",
+ "gemini" => "Twins",
+ "cancer" => "Crab",
+ "leo" => "Lion",
+ "virgo" => "Maiden",
+ "libra" => "Scales",
+ "scorpio" => "Scorpion",
+ "sagittarius" => "Archer",
+ "capricorn" => "Goat",
+ "aquarius" => "Water Bearer",
+ "pisces" => "Fish",
+
+ #--
+ "sun" => "Sun",
+
+ #--
+ "moon" => "Moon",
+ "phase" => "Phase",
+ "newmoon" => "New Moon",
+ "waxingcrescent" => "Waxing Crescent",
+ "firstquarter" => "First Quarter",
+ "waxingmoon" => "Waxing Moon",
+ "fullmoon" => "Full Moon",
+ "waningmoon" => "Waning Moon",
+ "lastquarter" => "Last Quarter",
+ "waningcrescent" => "Waning Crescent",
+ },
+
+ DE => {
+ "coord" => "Koordinaten",
+ "position" => "Position",
+ "longitude" => "Länge",
+ "latitude" => "Breite",
+ "altitude" => "Höhe ü. NHN",
+ "lonecl" => "Eklipt. Länge",
+ "latecl" => "Eklipt. Breite",
+ "ra" => "Rektaszension",
+ "dec" => "Deklination",
+ "az" => "Azimut",
+ "alt" => "Horizontwinkel",
+ "age" => "Alter",
+ "phase" => "Phase",
+ "rise" => "Aufgang",
+ "set" => "Untergang",
+ "transit" => "Kulmination",
+ "distance" => "Entfernung",
+ "diameter" => "Durchmesser",
+ "toobs" => "z. Beobachter",
+ "toce" => "z. Erdmittelpunkt",
+ "progress" => "Fortschritt",
+ "twilightcivil" => "Bürgerliche Dämmerung",
+ "twilightnautic" => "Nautische Dämmerung",
+ "twilightastro" => "Astronomische Dämmerung",
+ "twilightcustom" => "Konfigurierte Dämmerung",
+ "sign" => "Tierkreiszeichen",
+ "dst" => "Sommerzeit",
+ "nt" => "Normalzeit",
+ "hoursofsunlight" => "Tagesstunden",
+ "hoursofnight" => "Nachtstunden",
+ "hoursofvisibility" => "Sichtbarkeit",
+
+ #--
+ "time" => "Zeit",
+ "date" => "Datum",
+ "jdate" => "Julianisches Datum",
+ "dayofyear" => "Tag d. Jahres",
+ "days" => "Tage",
+ "timezone" => "Zeitzone",
+ "lmst" => "Lokale Sternzeit",
+
+ #--
+ "season" => "Astronomische Jahreszeit",
+ "spring" => "Frühling",
+ "summer" => "Sommer",
+ "fall" => "Herbst",
+ "winter" => "Winter",
+
+ #--
+ "aries" => "Widder",
+ "taurus" => "Stier",
+ "gemini" => "Zwillinge",
+ "cancer" => "Krebs",
+ "leo" => "Löwe",
+ "virgo" => "Jungfrau",
+ "libra" => "Waage",
+ "scorpio" => "Skorpion",
+ "sagittarius" => "Schütze",
+ "capricorn" => "Steinbock",
+ "aquarius" => "Wassermann",
+ "pisces" => "Fische",
+
+ #--
+ "sun" => "Sonne",
+
+ #--
+ "moon" => "Mond",
+ "phase" => "Phase",
+ "newmoon" => "Neumond",
+ "waxingcrescent" => "Zunehmende Sichel",
+ "firstquarter" => "Erstes Viertel",
+ "waxingmoon" => "Zunehmender Mond",
+ "fullmoon" => "Vollmond",
+ "waningmoon" => "Abnehmender Mond",
+ "lastquarter" => "Letztes Viertel",
+ "waningcrescent" => "Abnehmende Sichel",
+ },
+
+ ES => {
+ "coord" => "Coordenadas",
+ "position" => "Posición",
+ "longitude" => "Longitud",
+ "latitude" => "Latitud",
+ "altitude" => "Altura sobre el mar",
+ "lonecl" => "Longitud eclíptica",
+ "latecl" => "Latitud eclíptica",
+ "ra" => "Ascensión recta",
+ "dec" => "Declinación",
+ "az" => "Azimut",
+ "alt" => "Ángulo horizonte",
+ "age" => "Años",
+ "rise" => "Salida",
+ "set" => "Puesta",
+ "transit" => "Culminación",
+ "distance" => "Distancia",
+ "diameter" => "Diámetro",
+ "toobs" => "al observar",
+ "toce" => "al centro de la tierra",
+ "progress" => "Progreso",
+ "twilightcivil" => "Crepúsculo civil",
+ "twilightnautic" => "Crepúsculo náutico",
+ "twilightastro" => "Crepúsculo astronómico",
+ "twilightcustom" => "Crepúsculo personalizado",
+ "sign" => "Signo del zodiaco",
+ "dst" => "horario de verano",
+ "nt" => "tiempo estándar",
+ "hoursofsunlight" => "Horas de luz solar",
+ "hoursofnight" => "Horas de la noche",
+ "hoursofvisibility" => "Visibilidad",
+
+ #--
+ "time" => "Tiempo",
+ "date" => "Fecha",
+ "jdate" => "Fecha de Julian",
+ "dayofyear" => "Día del año",
+ "days" => "Días",
+ "timezone" => "Zona horaria",
+ "lmst" => "Hora sideral local",
+
+ #--
+ "season" => "Temporada Astronomica",
+ "spring" => "Primavera",
+ "summer" => "Verano",
+ "fall" => "Otoño",
+ "winter" => "Invierno",
+
+ #--
+ "aries" => "Aries",
+ "taurus" => "Tauro",
+ "gemini" => "Geminis",
+ "cancer" => "Cáncer",
+ "leo" => "León",
+ "virgo" => "Virgo",
+ "libra" => "Libra",
+ "scorpio" => "Escorpión",
+ "sagittarius" => "Sagitario",
+ "capricorn" => "Capricornio",
+ "aquarius" => "Acuario",
+ "pisces" => "Piscis",
+
+ #--
+ "sun" => "Sol",
+
+ #--
+ "moon" => "Luna",
+ "phase" => "Fase",
+ "newmoon" => "Luna nueva",
+ "waxingcrescent" => "Luna creciente",
+ "firstquarter" => "Primer cuarto",
+ "waxingmoon" => "Luna creciente",
+ "fullmoon" => "Luna llena",
+ "waningmoon" => "Luna menguante",
+ "lastquarter" => "Último cuarto",
+ "waningcrescent" => "Creciente menguante",
+ },
+
+ FR => {
+ "coord" => "Coordonnées",
+ "position" => "Position",
+ "longitude" => "Longitude",
+ "latitude" => "Latitude",
+ "altitude" => "Hauteur au dessus de la mer",
+ "lonecl" => "Longitude écliptique",
+ "latecl" => "Latitude écliptique",
+ "ra" => "Ascension droite",
+ "dec" => "Déclinaison",
+ "az" => "Azimut",
+ "alt" => "Angle horizon",
+ "age" => "Âge",
+ "rise" => "Lever",
+ "set" => "Coucher",
+ "transit" => "Culmination",
+ "distance" => "Distance",
+ "diameter" => "Diamètre",
+ "toobs" => "à l'observateur",
+ "toce" => "au centre de la terre",
+ "progress" => "Progrès",
+ "twilightcivil" => "Crépuscule civil",
+ "twilightnautic" => "Crépuscule nautique",
+ "twilightastro" => "Crépuscule astronomique",
+ "twilightcustom" => "Crépuscule personnalisé",
+ "sign" => "Signe du zodiaque",
+ "dst" => "heure d'été",
+ "nt" => "heure normale",
+ "hoursofsunlight" => "Heures de soleil",
+ "hoursofnight" => "Heures de la nuit",
+ "hoursofvisibility" => "Visibilité",
+
+ #--
+ "time" => "Temps",
+ "date" => "Date",
+ "jdate" => "Date de Julien",
+ "dayofyear" => "jour de l'année",
+ "days" => "jours",
+ "timezone" => "Fuseau horaire",
+ "lmst" => "Heure sidérale locale",
+
+ #--
+ "season" => "Saison Astronomique",
+ "spring" => "Printemps",
+ "summer" => "Été",
+ "fall" => "Automne",
+ "winter" => "Hiver",
+
+ #--
+ "aries" => "bélier",
+ "taurus" => "Taureau",
+ "gemini" => "Gémeaux",
+ "cancer" => "Cancer",
+ "leo" => "Lion",
+ "virgo" => "Jeune fille",
+ "libra" => "Balance",
+ "scorpio" => "Scorpion",
+ "sagittarius" => "Sagittaire",
+ "capricorn" => "Capricorne",
+ "aquarius" => "Verseau",
+ "pisces" => "Poissons",
+
+ #--
+ "sun" => "Soleil",
+
+ #--
+ "moon" => "Lune",
+ "phase" => "Phase",
+ "newmoon" => "Nouvelle lune",
+ "waxingcrescent" => "Croissant croissant",
+ "firstquarter" => "Premier quart",
+ "waxingmoon" => "Lune croissante",
+ "fullmoon" => "Pleine lune",
+ "waningmoon" => "Lune décroissante",
+ "lastquarter" => "Le dernier quart",
+ "waningcrescent" => "Croissant décroissant",
+ },
+
+ IT => {
+ "coord" => "Coordinate",
+ "position" => "Posizione",
+ "longitude" => "Longitudine",
+ "latitude" => "Latitudine",
+ "altitude" => "Altezza sopra il mare",
+ "lonecl" => "Longitudine ellittica",
+ "latecl" => "Latitudine eclittica",
+ "ra" => "Giusta ascensione",
+ "dec" => "Declinazione",
+ "az" => "Azimut",
+ "alt" => "Angolo di orizzonte",
+ "age" => "Età",
+ "rise" => "Crescente",
+ "set" => "Affondamento",
+ "transit" => "Culmine",
+ "distance" => "Distanza",
+ "diameter" => "Diametro",
+ "toobs" => "verso l'osservatore",
+ "toce" => "verso centro della terra",
+ "progress" => "Progresso",
+ "twilightcivil" => "Crepuscolo civile",
+ "twilightnautic" => "Crepuscolo nautico",
+ "twilightastro" => "Crepuscolo astronomico",
+ "twilightcustom" => "Crepuscolo personalizzato",
+ "sign" => "Segno zodiacale",
+ "dst" => "ora legale",
+ "nt" => "ora standard",
+ "hoursofsunlight" => "Ore di luce solare",
+ "hoursofnight" => "Ore della notte",
+ "hoursofvisibility" => "Visibilità",
+
+ #--
+ "time" => "Tempo",
+ "date" => "Data",
+ "jdate" => "Data giuliana",
+ "dayofyear" => "giorno dell'anno",
+ "days" => "giorni",
+ "timezone" => "Fuso orario",
+ "lmst" => "Tempo siderale locale",
+
+ #--
+ "season" => "Stagione Astronomica",
+ "spring" => "Stagione primaverile",
+ "summer" => "Estate",
+ "fall" => "Autunno",
+ "winter" => "Inverno",
+
+ #--
+ "aries" => "Ariete",
+ "taurus" => "Toro",
+ "gemini" => "Gemelli",
+ "cancer" => "Cancro",
+ "leo" => "Leone",
+ "virgo" => "Vergine",
+ "libra" => "Libra",
+ "scorpio" => "Scorpione",
+ "sagittarius" => "Arciere",
+ "capricorn" => "Capricorno",
+ "aquarius" => "Acquario",
+ "pisces" => "Pesci",
+
+ #--
+ "sun" => "Sole",
+
+ #--
+ "moon" => "Luna",
+ "phase" => "Fase",
+ "newmoon" => "Nuova luna",
+ "waxingcrescent" => "Luna crescente",
+ "firstquarter" => "Primo quarto",
+ "waxingmoon" => "Luna crescente",
+ "fullmoon" => "Luna piena",
+ "waningmoon" => "Luna calante",
+ "lastquarter" => "Ultimo quarto",
+ "waningcrescent" => "Pericolo crescente",
+ },
+
+ NL => {
+ "coord" => "Coördinaten",
+ "position" => "Positie",
+ "longitude" => "Lengtegraad",
+ "latitude" => "Breedtegraad",
+ "altitude" => "Hoogte b. Zee",
+ "lonecl" => "Eclipticale Lengtegraad",
+ "latecl" => "Eclipticale Breedtegraad",
+ "ra" => "Juiste klimming",
+ "dec" => "Declinatie",
+ "az" => "Azimuth",
+ "alt" => "Horizon Angle",
+ "age" => "Leeftijd",
+ "rise" => "Opkomst",
+ "set" => "Ondergang",
+ "transit" => "Culminatie",
+ "distance" => "Afstand",
+ "diameter" => "Diameter",
+ "toobs" => "voor de Waarnemer",
+ "toce" => "naar het Middelpunt van de Aarde",
+ "progress" => "Vooruitgang",
+ "twilightcivil" => "Burgerlijke Schemering",
+ "twilightnautic" => "Nautische Schemering",
+ "twilightastro" => "Astronomische Schemering",
+ "twilightcustom" => "Aangepaste Schemering",
+ "sign" => "Sterrenbeeld",
+ "dst" => "Zomertijd",
+ "nt" => "Standaard Tijd",
+ "hoursofsunlight" => "Dagen Uur",
+ "hoursofnight" => "Uren van de Nacht",
+ "hoursofvisibility" => "Zichtbaarheid",
+
+ #--
+ "time" => "Tijd",
+ "date" => "Datum",
+ "jdate" => "Juliaanse Datum",
+ "dayofyear" => "Dag van het Jaar",
+ "days" => "Dagen",
+ "timezone" => "Tijdzone",
+ "lmst" => "Lokale Sterrentijd",
+
+ #--
+ "season" => "Astronomisch Seizoen",
+ "spring" => "De lente",
+ "summer" => "Zomer",
+ "fall" => "Herfst",
+ "winter" => "Winter",
+
+ #--
+ "aries" => "Ram",
+ "taurus" => "Stier",
+ "gemini" => "Tweelingen",
+ "cancer" => "Kanker",
+ "leo" => "Leeuw",
+ "virgo" => "Maagd",
+ "libra" => "Weegschaal",
+ "scorpio" => "Schorpioen",
+ "sagittarius" => "Boogschutter",
+ "capricorn" => "Steenbok",
+ "aquarius" => "Waterman",
+ "pisces" => "Vis",
+
+ #--
+ "sun" => "Zon",
+
+ #--
+ "moon" => "Maan",
+ "phase" => "Fase",
+ "newmoon" => "Nieuwe Maan",
+ "waxingcrescent" => "Wassende halve Maan",
+ "firstquarter" => "Eerste Kwartier",
+ "waxingmoon" => "Wassende Maan",
+ "fullmoon" => "Volle Maan",
+ "waningmoon" => "Afnemende Maan",
+ "lastquarter" => "Het laatste Kwartier",
+ "waningcrescent" => "Afnemende halve Maan",
+ },
+
+ PL => {
+ "coord" => "Współrzędne",
+ "position" => "Pozycja",
+ "longitude" => "Długość",
+ "latitude" => "Szerokość",
+ "altitude" => "Wysokość nad morzem",
+ "lonecl" => "Długość ekliptyczna",
+ "latecl" => "Szerokość ekliptyczna",
+ "ra" => "Rektascencja",
+ "dec" => "Deklinacja",
+ "az" => "Azymut",
+ "alt" => "Kąt horyzont",
+ "age" => "Wiek",
+ "rise" => "Wschód",
+ "set" => "Zachód",
+ "transit" => "Kulminacja",
+ "distance" => "Dystans",
+ "diameter" => "Średnica",
+ "toobs" => "w kierunku obserwatora",
+ "toce" => "w kierunku środka ziemi",
+ "progress" => "Postęp",
+ "twilightcivil" => "Zmierzch cywilny",
+ "twilightnautic" => "Zmierzch morski",
+ "twilightastro" => "Zmierzch astronomiczny",
+ "twilightcustom" => "Zmierzch niestandardowy",
+ "sign" => "Znak zodiaku",
+ "dst" => "czas letni",
+ "nt" => "standardowy czas",
+ "hoursofsunlight" => "Godziny światła słonecznego",
+ "hoursofnight" => "Godziny nocy",
+ "hoursofvisibility" => "Widoczność",
+
+ #--
+ "time" => "Czas",
+ "date" => "Data",
+ "jdate" => "Juliańska data",
+ "dayofyear" => "dzień roku",
+ "days" => "dni",
+ "timezone" => "Strefa czasowa",
+ "lmst" => "Lokalny czas gwiazdowy",
+
+ #--
+ "season" => "Sezon Astronomiczny",
+ "spring" => "Wiosna",
+ "summer" => "Lato",
+ "fall" => "Jesień",
+ "winter" => "Zima",
+
+ #--
+ "aries" => "Baran",
+ "taurus" => "Byk",
+ "gemini" => "Bliźnięta",
+ "cancer" => "Rak",
+ "leo" => "Lew",
+ "virgo" => "Panna",
+ "libra" => "Libra",
+ "scorpio" => "Skorpion",
+ "sagittarius" => "Strzelec",
+ "capricorn" => "Koziorożec",
+ "aquarius" => "Wodnik",
+ "pisces" => "Ryby",
+
+ #--
+ "sun" => "Słońce",
+
+ #--
+ "moon" => "Księżyc",
+ "phase" => "Faza",
+ "newmoon" => "Nów",
+ "waxingcrescent" => "Półksiężyc woskowy",
+ "firstquarter" => "Pierwszym kwartale",
+ "waxingmoon" => "Księżyc przybywający",
+ "fullmoon" => "Pełnia księżyca",
+ "waningmoon" => "Zmniejszający się księżyc",
+ "lastquarter" => "Ostatni kwartał",
+ "waningcrescent" => "Zwiększający się księżyc",
+ }
+);
+
+our @zodiac = ("aries","taurus","gemini","cancer","leo","virgo",
"libra","scorpio","sagittarius","capricorn","aquarius","pisces");
-my @phases = ("newmoon","waxingcrescent", "firstquarter", "waxingmoon",
+our @phases = ("newmoon","waxingcrescent", "firstquarter", "waxingmoon",
"fullmoon", "waningmoon", "lastquarter", "waningcrescent");
-my @seasons = (
- "winter","spring","summer","fall");
-
-my %seasonn = (
- "spring" => [80,172], #21./22.3. - 20.6.
- "summer" => [173,265], #21.06. bis 21./22.09.
- "fall" => [266,353], #22./23.09. bis 20./21.12.
- "winter" => [354,79]
+our @seasons = ( "winter", "spring", "summer", "fall" );
+
+our %seasonn = (
+ "spring" => [ 80, 172 ], #21./22.3. - 20.6.
+ "summer" => [ 173, 265 ], #21.06. bis 21./22.09.
+ "fall" => [ 266, 353 ], #22./23.09. bis 20./21.12.
+ "winter" => [ 354, 79 ]
+);
+
+#-- Run before package compilation
+BEGIN {
+
+ # Import from main context
+ GP_Import(
+ qw(
+ attr
+ AttrVal
+ data
+ Debug
+ defs
+ deviceEvents
+ FmtDateTime
+ FW_pO
+ FW_RET
+ FW_RETTYPE
+ FW_webArgs
+ GetType
+ init_done
+ InternalTimer
+ IsDisabled
+ Log
+ Log3
+ maxNum
+ minNum
+ modules
+ readingFnAttributes
+ readingsBeginUpdate
+ readingsBulkUpdateIfChanged
+ readingsEndUpdate
+ readingsSingleUpdate
+ RemoveInternalTimer
+ time_str2num
+ toJSON
+ )
);
-
-sub Astro_SunRise($$$$$$);
-sub Astro_MoonRise($$$$$$$);
-
+}
+
+#-- Export to main context with different name
+_Export(
+ qw(
+ Get
+ Initialize
+ )
+);
+
+_LoadOptionalPackages();
+
+sub SunRise($$$$$$$$);
+sub MoonRise($$$$$$$);
+sub SetTime(;$$$);
+sub Compute($;$);
+
########################################################################################################
#
-# Astro_Initialize
+# Initialize
#
-# Parameter hash = hash of device addressed
+# Parameter hash = hash of device addressed
#
########################################################################################################
-sub Astro_Initialize ($) {
+sub Initialize ($) {
my ($hash) = @_;
- $hash->{DefFn} = "Astro_Define";
- #$hash->{SetFn} = "Astro_Set";
- $hash->{GetFn} = "Astro_Get";
- $hash->{UndefFn} = "Astro_Undef";
- $hash->{AttrFn} = "Astro_Attr";
- $hash->{AttrList} = "interval longitude latitude altitude horizon ".$readingFnAttributes;;
-
- $data{FWEXT}{"/Astro_moonwidget"}{FUNC} = "Astro_moonwidget";
- $data{FWEXT}{"/Astr_moonwidget"}{FORKABLE} = 0;
+ $hash->{DefFn} = "FHEM::Astro::Define";
+ $hash->{SetFn} = "FHEM::Astro::Set";
+ $hash->{GetFn} = "FHEM::Astro::Get";
+ $hash->{UndefFn} = "FHEM::Astro::Undef";
+ $hash->{AttrFn} = "FHEM::Astro::Attr";
+ $hash->{NotifyFn} = "FHEM::Astro::Notify";
+ $hash->{AttrList} = join (" ", map {
+ defined($attrs{$_}) ? "$_:$attrs{$_}" : $_
+ } sort keys %attrs
+ )
+ ." "
+ .$readingFnAttributes;
+
+ $hash->{parseParams} = 1;
+
+ $data{FWEXT}{"/Astro_moonwidget"}{FUNC} = "FHEM::Astro::Moonwidget";
+ $data{FWEXT}{"/Astro_moonwidget"}{FORKABLE} = 0;
- return undef;
+ return FHEM::Meta::InitMod( __FILE__, $hash );
}
########################################################################################################
#
-# Astro_Define - Implements DefFn function
+# Define - Implements DefFn function
#
-# Parameter hash = hash of device addressed, def = definition string
+# Parameter hash = hash of device addressed, a = array of arguments, h = hash of parameters
#
########################################################################################################
-sub Astro_Define ($$) {
- my ($hash, $def) = @_;
- #my $now = time();
- my $name = $hash->{NAME};
- $hash->{VERSION} = $astroversion;
- readingsSingleUpdate( $hash, "state", "Initialized", 1 );
+sub Define ($@) {
+ my ($hash,$a,$h) = @_;
+ my $name = shift @$a;
+ my $type = shift @$a;
+
+ return $@ unless ( FHEM::Meta::SetInternals($hash) );
+ use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
+
+ # $hash->{VERSION} = $VERSION;
+ $hash->{NOTIFYDEV} = "global";
+ $hash->{INTERVAL} = 3600;
+ readingsSingleUpdate( $hash, "state", "Initialized", $init_done );
$modules{Astro}{defptr}{$name} = $hash;
-
- RemoveInternalTimer($hash);
-
- #-- Call us in n seconds again.
- InternalTimer(gettimeofday()+ 60, "Astro_Update", $hash,0);
+
+ # for the very first definition, set some default attributes
+ if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
+ $attr{$name}{icon} = 'telescope';
+ $attr{$name}{recomputeAt} = 'NewDay,SunRise,SunSet,AstroTwilightEvening,AstroTwilightMorning,CivilTwilightEvening,CivilTwilightMorning,CustomTwilightEvening,CustomTwilightMorning
+';
+ }
return undef;
}
########################################################################################################
#
-# Astro_Undef - Implements Undef function
+# Undef - Implements Undef function
#
-# Parameter hash = hash of device addressed, def = definition string
+# Parameter hash = hash of device addressed, arg = array of arguments
#
########################################################################################################
-sub Astro_Undef ($$) {
+sub Undef ($$) {
my ($hash,$arg) = @_;
RemoveInternalTimer($hash);
@@ -317,13 +784,90 @@ sub Astro_Undef ($$) {
########################################################################################################
#
-# Astro_Attr - Implements Attr function
+# Notify - Implements Notify function
#
-# Parameter hash = hash of device addressed, ???
+# Parameter hash = hash of device addressed, dev = hash of device that triggered notification
#
########################################################################################################
-sub Astro_Attr(@) {
+sub Notify ($$) {
+ my ($hash,$dev) = @_;
+ my $name = $hash->{NAME};
+ my $TYPE = $hash->{TYPE};
+ my $devName = $dev->{NAME};
+ my $devType = GetType($devName);
+
+ if ( $devName eq "global" ) {
+ my $events = deviceEvents( $dev, 1 );
+ return "" unless ($events);
+
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+ next if ( $event =~ m/^[A-Za-z\d_-]+:/ );
+
+ if ( $event =~ m/^INITIALIZED|REREADCFG$/ ) {
+ if ( ( defined( $hash->{INTERVAL} ) && $hash->{INTERVAL} > 0 )
+ || defined( $hash->{RECOMPUTEAT} ) )
+ {
+ RemoveInternalTimer($hash);
+ InternalTimer(gettimeofday()+5,"FHEM::Astro::Update",$hash,0);
+ }
+ }
+ elsif ( $event =~
+ m/^(DEFINED|MODIFIED)\s+([A-Za-z\d_-]+)$/ &&
+ $2 eq $name )
+ {
+ if ( ( defined( $hash->{INTERVAL} ) && $hash->{INTERVAL} > 0 )
+ || defined( $hash->{RECOMPUTEAT} ) )
+ {
+ RemoveInternalTimer($hash);
+ InternalTimer(gettimeofday()+1,"FHEM::Astro::Update",$hash,0);
+ }
+ }
+
+ # only process attribute events
+ next
+ unless ( $event =~
+m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/
+ );
+
+ my $cmd = $1;
+ my $d = $2;
+ my $attr = $3;
+ my $val = $4;
+ my $type = GetType($d);
+
+ # filter attributes to be processed
+ next
+ unless ( $attr eq "altitude"
+ || $attr eq "language"
+ || $attr eq "latitude"
+ || $attr eq "lc_numeric"
+ || $attr eq "lc_time"
+ || $attr eq "longitude"
+ || $attr eq "timezone" );
+
+ # when global attributes were changed
+ if ( $d eq "global" ) {
+ RemoveInternalTimer($hash);
+ InternalTimer( gettimeofday() + 1,
+ "FHEM::Astro::Update", $hash, 0 );
+ }
+ }
+ }
+
+ return undef;
+}
+
+########################################################################################################
+#
+# Attr - Implements Attr function
+#
+# Parameter do = action, name = name of device, key = attribute name, value = attribute value
+#
+########################################################################################################
+
+sub Attr(@) {
my ($do,$name,$key,$value) = @_;
my $hash = $defs{$name};
@@ -331,28 +875,89 @@ sub Astro_Attr(@) {
if ( $do eq "set") {
ARGUMENT_HANDLER: {
+ #-- altitude modified at runtime
+ $key eq "altitude" and do {
+ #-- check value
+ return "[Astro] $do $name attribute $key must be a float number >= 0 meters"
+ unless($value =~ m/^(\d+(?:\.\d+)?)$/ && $1 >= 0.);
+ };
+ #-- disable modified at runtime
+ $key eq "disable" and do {
+ #-- check value
+ return "[Astro] $do $name attribute $key can only be 1 or 0"
+ unless($value =~ m/^(1|0)$/);
+ readingsSingleUpdate($hash,"state",$value?"inactive":"Initialized",$init_done);
+ };
+ #-- horizon modified at runtime
+ $key eq "horizon" and do {
+ #-- check value
+ return "[Astro] $do $name attribute $key must be a float number >= -45 and <= 45 degrees"
+ unless($value =~ m/^(-?\d+(?:\.\d+)?)(?::(-?\d+(?:\.\d+)?))?$/ && $1 >= -45. && $1 <= 45. && (!$2 || $2 >= -45. && $2 <= 45.));
+ };
#-- interval modified at runtime
$key eq "interval" and do {
#-- check value
- return "[Astro] set $name interval must be >= 0" if(int($value) < 0);
+ return "[Astro] $do $name attribute $key must be >= 0 seconds"
+ unless($value =~ m/^\d+$/);
#-- update timer
- $hash->{INTERVAL} = int($value);
- if ($init_done) {
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Astro_Update", $hash, 0);
+ $hash->{INTERVAL} = $value;
+ };
+ #-- latitude modified at runtime
+ $key eq "latitude" and do {
+ #-- check value
+ return "[Astro] $do $name attribute $key must be float number >= -90 and <= 90 degrees"
+ unless($value =~ m/^(-?\d+(?:\.\d+)?)$/ && $1 >= -90. && $1 <= 90.);
+ };
+ #-- longitude modified at runtime
+ $key eq "longitude" and do {
+ #-- check value
+ return "[Astro] $do $name attribute $key must be float number >= -180 and <= 180 degrees"
+ unless($value =~ m/^(-?\d+(?:\.\d+)?)$/ && $1 >= -180. && $1 <= 180.);
+ };
+ #-- recomputeAt modified at runtime
+ $key eq "recomputeAt" and do {
+ my @skel = split(',', $attrs{recomputeAt});
+ shift @skel;
+ #-- check value 1/2
+ return "[Astro] $do $name attribute $key must be one or many of ".join(',', @skel)
+ if(!$value || $value eq "");
+ #-- check value 2/2
+ my @vals = split(',', $value);
+ foreach my $val (@vals) {
+ return "[Astro] $do $name attribute value $val is invalid, must be one or many of ".join(',', @skel)
+ unless(grep( m/^$val$/, @skel ));
}
- last;
+ $hash->{RECOMPUTEAT} = join(',', @vals);
};
}
}
+
+ elsif ( $do eq "del") {
+ readingsSingleUpdate($hash,"state","Initialized",$init_done)
+ if ($key eq "disable");
+ $hash->{INTERVAL} = 3600
+ if ($key eq "interval");
+ delete $hash->{RECOMPUTEAT}
+ if ($key eq "recomputeAt");
+ }
+
+ if ( $init_done
+ && exists( $attrs{$key} )
+ && ( $hash->{INTERVAL} > 0 || $hash->{RECOMPUTEAT} || $hash->{NEXTUPDATE} )
+ )
+ {
+ RemoveInternalTimer($hash);
+ InternalTimer( gettimeofday() + 2, "FHEM::Astro::Update", $hash, 0 );
+ }
+
return $ret;
}
-sub Astro_mod($$) { my ($a,$b)=@_;if( $a =~ /\d*\.\d*/){return($a-floor($a/$b)*$b)}else{return undef}; }
-sub Astro_mod2Pi($) { my ($x)=@_;$x = Astro_mod($x, 2.*pi);return($x); }
-sub Astro_round($$) { my ($x,$n)=@_; return int(10**$n*$x+0.5)/10**$n};
+sub _mod($$) { my ($a,$b)=@_;if( $a =~ /\d*\.\d*/){return($a-floor($a/$b)*$b)}else{return undef}; }
+sub _mod2Pi($) { my ($x)=@_;$x = _mod($x, 2.*pi);return($x); }
+sub _round($$) { my ($x,$n)=@_; return int(10**$n*$x+0.5)/10**$n};
-sub Astro_tzoffset($) {
+sub _tzoffset($) {
my ($t) = @_;
my $utc = mktime(gmtime($t));
#-- the following does not properly calculate dst
@@ -366,26 +971,131 @@ sub Astro_tzoffset($) {
return (($local - $utc)/36);
}
+########################################################################################################
+#
+# _Export - Export references to main context using a different naming schema
+#
+########################################################################################################
+
+sub _Export {
+ no strict qw/refs/; ## no critic
+ my $pkg = caller(0);
+ my $main = $pkg;
+ $main =~ s/^(?:.+::)?([^:]+)$/main::$1\_/g;
+ foreach (@_) {
+ *{ $main . $_ } = *{ $pkg . '::' . $_ };
+ }
+}
+
+########################################################################################################
+#
+# _LoadOptionalPackages - Load Perl packages that may not be installed
+#
+########################################################################################################
+
+sub _LoadOptionalPackages {
+
+ # JSON preference order
+ local $ENV{PERL_JSON_BACKEND} =
+ 'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP'
+ unless ( defined( $ENV{PERL_JSON_BACKEND} ) );
+
+ # try to use JSON::MaybeXS wrapper
+ # for chance of better performance + open code
+ eval {
+ require JSON::MaybeXS;
+ $json = JSON::MaybeXS->new;
+ 1;
+ };
+ if ($@) {
+ $@ = undef;
+
+ # try to use JSON wrapper
+ # for chance of better performance
+ eval {
+ require JSON;
+ $json = JSON->new;
+ 1;
+ };
+
+ if ($@) {
+ $@ = undef;
+
+ # In rare cases, Cpanel::JSON::XS may
+ # be installed but JSON|JSON::MaybeXS not ...
+ eval {
+ require Cpanel::JSON::XS;
+ $json = Cpanel::JSON::XS->new;
+ 1;
+ };
+
+ if ($@) {
+ $@ = undef;
+
+ # In rare cases, JSON::XS may
+ # be installed but JSON not ...
+ eval {
+ require JSON::XS;
+ $json = JSON::XS->new;
+ 1;
+ };
+
+ if ($@) {
+ $@ = undef;
+
+ # Fallback to built-in JSON which SHOULD
+ # be available since 5.014 ...
+ eval {
+ require JSON::PP;
+ $json = JSON::PP->new;
+ 1;
+ };
+
+ if ($@) {
+ $@ = undef;
+
+ # Last chance may be a backport
+ eval {
+ require JSON::backportPP;
+ $json = JSON::backportPP->new;
+ 1;
+ };
+ $@ = undef if ($@);
+ }
+ }
+ }
+ }
+ }
+
+ if ($@) {
+ $@ = undef;
+ } else {
+ $json->allow_nonref;
+ $json->shrink;
+ $json->utf8;
+ }
+}
+
########################################################################################################
#
# time fragments into minutes, seconds
#
########################################################################################################
-sub Astro_HHMM($){
+sub HHMM($){
my ($hh) = @_;
return("---")
- if (!defined($hh) || $hh !~ /\d*\.\d*/) ;
+ if (!defined($hh) || $hh !~ /^-?\d+/ || $hh==0) ;
my $h = floor($hh);
my $m = ($hh-$h)*60.;
return sprintf("%02d:%02d",$h,$m);
}
-sub Astro_HHMMSS($){
+sub HHMMSS($){
my ($hh) = @_;
- return("")
- if ($hh==0) ;
+ return("---")
+ if (!defined($hh) || $hh !~ /^-?\d+/ || $hh==0) ;
my $m = ($hh-floor($hh))*60.;
my $s = ($m-floor($m))*60;
@@ -395,11 +1105,11 @@ sub Astro_HHMMSS($){
########################################################################################################
#
-# Astro_CalcJD - Calculate Julian date: valid only from 1.3.1901 to 28.2.2100
+# CalcJD - Calculate Julian date: valid only from 1.3.1901 to 28.2.2100
#
########################################################################################################
-sub Astro_CalcJD($$$) {
+sub CalcJD($$$) {
my ($day,$month,$year) = @_;
my $jd = 2415020.5-64; # 1.1.1900 - correction of algorithm
if ($month<=2) {
@@ -413,11 +1123,11 @@ sub Astro_CalcJD($$$) {
########################################################################################################
#
-# Astro_GMST - Julian Date to Greenwich Mean Sidereal Time
+# GMST - Julian Date to Greenwich Mean Sidereal Time
#
########################################################################################################
-sub Astro_GMST($){
+sub GMST($){
my ($JD) = @_;
my $UT = ($JD-0.5) - int($JD-0.5);
$UT = $UT*24.; # UT in hours
@@ -425,51 +1135,51 @@ sub Astro_GMST($){
my $T = ($JD-2451545.0)/36525.0;
my $T0 = 6.697374558 + $T*(2400.051336 + $T*0.000025862);
- return( Astro_mod($T0+$UT*1.002737909,24.));
+ return( _mod($T0+$UT*1.002737909,24.));
}
########################################################################################################
#
-# Astro_GMST2UT - Convert Greenweek mean sidereal time to UT
+# GMST2UT - Convert Greenweek mean sidereal time to UT
#
########################################################################################################
-sub Astro_GMST2UT($$){
+sub GMST2UT($$){
my ($JD, $gmst) = @_;
$JD = floor($JD-0.5)+0.5; # JD at 0 hours UT
my $T = ($JD-2451545.0)/36525.0;
- my $T0 = Astro_mod(6.697374558 + $T*(2400.051336 + $T*0.000025862), 24.);
+ my $T0 = _mod(6.697374558 + $T*(2400.051336 + $T*0.000025862), 24.);
my $UT = 0.9972695663*(($gmst-$T0));
return($UT);
}
########################################################################################################
#
-# Astro_GMST2LMST - Local Mean Sidereal Time, geographical longitude in radians,
+# GMST2LMST - Local Mean Sidereal Time, geographical longitude in radians,
# East is positive
#
########################################################################################################
-sub Astro_GMST2LMST($$){
+sub GMST2LMST($$){
my ($gmst, $lon) = @_;
- my $lmst = Astro_mod($gmst+$RAD*$lon/15, 24.);
+ my $lmst = _mod($gmst+$RAD*$lon/15, 24.);
return( $lmst );
}
########################################################################################################
#
-# Astro_Ecl2Equ - Transform ecliptical coordinates (lon/lat) to equatorial coordinates (RA/dec)
+# Ecl2Equ - Transform ecliptical coordinates (lon/lat) to equatorial coordinates (RA/dec)
#
########################################################################################################
-sub Astro_Ecl2Equ($$$){
+sub Ecl2Equ($$$){
my ($lon, $lat, $TDT) = @_;
my $T = ($TDT-2451545.0)/36525.; # Epoch 2000 January 1.5
my $eps = (23.+(26+21.45/60.)/60. + $T*(-46.815 +$T*(-0.0006 + $T*0.00181) )/3600. )*$DEG;
my $coseps = cos($eps);
my $sineps = sin($eps);
my $sinlon = sin($lon);
- my $ra = Astro_mod2Pi(atan2( ($sinlon*$coseps-tan($lat)*$sineps), cos($lon) ));
+ my $ra = _mod2Pi(atan2( ($sinlon*$coseps-tan($lat)*$sineps), cos($lon) ));
my $dec = asin( sin($lat)*$coseps + cos($lat)*$sineps*$sinlon );
return ($ra,$dec);
@@ -477,12 +1187,12 @@ sub Astro_Ecl2Equ($$$){
########################################################################################################
#
-# Astro_Equ2Altaz - Transform equatorial coordinates (RA/Dec) to horizonal coordinates
+# Equ2Altaz - Transform equatorial coordinates (RA/Dec) to horizonal coordinates
# (azimuth/altitude). Refraction is ignored
#
########################################################################################################
-sub Astro_Equ2Altaz($$$$$){
+sub Equ2Altaz($$$$$){
my ($ra, $dec, $TDT, $lat, $lmst)=@_;
my $cosdec = cos($dec);
my $sindec = sin($dec);
@@ -494,7 +1204,7 @@ sub Astro_Equ2Altaz($$$$$){
my $N = -$cosdec * $sinlha;
my $D = $sindec * $coslat - $cosdec * $coslha * $sinlat;
- my $az = Astro_mod2Pi( atan2($N, $D) );
+ my $az = _mod2Pi( atan2($N, $D) );
my $alt = asin( $sindec * $sinlat + $cosdec * $coslha * $coslat );
return ($az,$alt);
@@ -502,12 +1212,12 @@ sub Astro_Equ2Altaz($$$$$){
########################################################################################################
#
-# Astro_GeoEqu2TopoEqu - Transform geocentric equatorial coordinates (RA/Dec) to
+# GeoEqu2TopoEqu - Transform geocentric equatorial coordinates (RA/Dec) to
# topocentric equatorial coordinates
#
########################################################################################################
-sub Astro_GeoEqu2TopoEqu($$$$$$$){
+sub GeoEqu2TopoEqu($$$$$$$){
my ($ra, $dec, $distance, $lon, $lat, $radius, $lmst) = @_;
my $cosdec = cos($dec);
@@ -524,18 +1234,18 @@ sub Astro_GeoEqu2TopoEqu($$$$$$$){
my $distanceTopocentric = sqrt($x*$x + $y*$y + $z*$z);
my $decTopocentric = asin($z/$distanceTopocentric);
- my $raTopocentric = Astro_mod2Pi( atan2($y, $x) );
+ my $raTopocentric = _mod2Pi( atan2($y, $x) );
return ( ($distanceTopocentric,$decTopocentric,$raTopocentric) );
}
########################################################################################################
#
-# Astro_EquPolar2Cart - Calculate cartesian from polar coordinates
+# EquPolar2Cart - Calculate cartesian from polar coordinates
#
########################################################################################################
-sub Astro_EquPolar2Cart($$$){
+sub EquPolar2Cart($$$){
my ($lon,$lat,$distance) = @_;
my $rcd = cos($lat)*$distance;
my $x = $rcd*cos($lon);
@@ -546,13 +1256,13 @@ sub Astro_EquPolar2Cart($$$){
########################################################################################################
#
-# Astro_Observer2EquCart - Calculate observers cartesian equatorial coordinates (x,y,z in celestial frame)
+# Observer2EquCart - Calculate observers cartesian equatorial coordinates (x,y,z in celestial frame)
# from geodetic coordinates (longitude, latitude, height above WGS84 ellipsoid)
# Currently only used to calculate distance of a body from the observer
#
########################################################################################################
-sub Astro_Observer2EquCart($$$$){
+sub Observer2EquCart($$$$){
my ($lon, $lat, $height, $gmst ) = @_;
my $flat = 298.257223563; # WGS84 flatening of earth
@@ -574,7 +1284,7 @@ sub Astro_Observer2EquCart($$$$){
if ($lat < 0.0) { $y = -$y; } # adjust sign
#-- convert from geocentric polar to geocentric cartesian, with regard to Greenwich
- ($x,$y,$z) = Astro_EquPolar2Cart( $x, $y, $radius );
+ ($x,$y,$z) = EquPolar2Cart( $x, $y, $radius );
#-- rotate around earth's polar axis to align coordinate system from Greenwich to vernal equinox
my $rotangle = $gmst/24*2*pi; # sideral time gmst given in hours. Convert to radians
@@ -586,13 +1296,13 @@ sub Astro_Observer2EquCart($$$$){
########################################################################################################
#
-# Astro_SunPosition - Calculate coordinates for Sun
+# SunPosition - Calculate coordinates for Sun
# Coordinates are accurate to about 10s (right ascension)
# and a few minutes of arc (declination)
#
########################################################################################################
-sub Astro_SunPosition($$$){
+sub SunPosition($$$){
my ($TDT, $observerlat, $lmst)=@_;
my $D = $TDT-2447891.5;
@@ -608,7 +1318,7 @@ sub Astro_SunPosition($$$){
my %sunCoor;
- $sunCoor{lon} = Astro_mod2Pi($nu+$wg);
+ $sunCoor{lon} = _mod2Pi($nu+$wg);
$sunCoor{lat} = 0;
$sunCoor{anomalyMean} = $MSun;
@@ -617,11 +1327,11 @@ sub Astro_SunPosition($$$){
$sunCoor{distance} = $distance*$a; # distance in km
$sunCoor{parallax} = 6378.137/$sunCoor{distance}; # horizonal parallax
- ($sunCoor{ra},$sunCoor{dec}) = Astro_Ecl2Equ($sunCoor{lon}, $sunCoor{lat}, $TDT);
+ ($sunCoor{ra},$sunCoor{dec}) = Ecl2Equ($sunCoor{lon}, $sunCoor{lat}, $TDT);
#-- calculate horizonal coordinates of sun, if geographic positions is given
if (defined($observerlat) && defined($lmst) ) {
- ($sunCoor{az},$sunCoor{alt}) = Astro_Equ2Altaz($sunCoor{ra}, $sunCoor{dec}, $TDT, $observerlat, $lmst);
+ ($sunCoor{az},$sunCoor{alt}) = Equ2Altaz($sunCoor{ra}, $sunCoor{dec}, $TDT, $observerlat, $lmst);
}
$sunCoor{sig} = $zodiac[floor($sunCoor{lon}*$RAD/30)];
@@ -630,12 +1340,12 @@ sub Astro_SunPosition($$$){
########################################################################################################
#
-# Astro_MoonPosition - Calculate data and coordinates for the Moon
+# MoonPosition - Calculate data and coordinates for the Moon
# Coordinates are accurate to about 1/5 degree (in ecliptic coordinates)
#
########################################################################################################
-sub Astro_MoonPosition($$$$$$$){
+sub MoonPosition($$$$$$$){
my ($sunlon, $sunanomalyMean, $TDT, $observerlon, $observerlat, $observerradius, $lmst) = @_;
my $D = $TDT-2447891.5;
@@ -667,11 +1377,11 @@ sub Astro_MoonPosition($$$$$$$){
my $N2 = $N-0.16*$DEG*sin($sunanomalyMean);
my %moonCoor;
- $moonCoor{lon} = Astro_mod2Pi( $N2 + atan2( sin($l3-$N2)*cos($i), cos($l3-$N2) ) );
+ $moonCoor{lon} = _mod2Pi( $N2 + atan2( sin($l3-$N2)*cos($i), cos($l3-$N2) ) );
$moonCoor{lat} = asin( sin($l3-$N2)*sin($i) );
$moonCoor{orbitLon} = $l3;
- ($moonCoor{ra},$moonCoor{dec}) = Astro_Ecl2Equ($moonCoor{lon},$moonCoor{lat},$TDT);
+ ($moonCoor{ra},$moonCoor{dec}) = Ecl2Equ($moonCoor{lon},$moonCoor{lat},$TDT);
#-- relative distance to semi mayor axis of lunar oribt
my $distance = (1-$e*$e) / (1+$e*cos($MMoon2+$Ec) );
$moonCoor{diameter} = $diameter0/$distance; # angular diameter in radians
@@ -688,19 +1398,19 @@ sub Astro_MoonPosition($$$$$$$){
if (defined($observerlat) && defined($observerlon) && defined($lmst) ) {
#-- transform geocentric coordinates into topocentric (==observer based) coordinates
my ($distanceTopocentric,$decTopocentric,$raTopocentric) =
- Astro_GeoEqu2TopoEqu($moonCoor{ra}, $moonCoor{dec}, $moonCoor{distance}, $observerlon, $observerlat, $observerradius, $lmst);
+ GeoEqu2TopoEqu($moonCoor{ra}, $moonCoor{dec}, $moonCoor{distance}, $observerlon, $observerlat, $observerradius, $lmst);
#-- now ra and dec are topocentric
$moonCoor{ra} = $raTopocentric;
$moonCoor{dec} = $decTopocentric;
- ($moonCoor{az},$moonCoor{alt})= Astro_Equ2Altaz($moonCoor{ra}, $moonCoor{dec}, $TDT, $observerlat, $lmst);
+ ($moonCoor{az},$moonCoor{alt})= Equ2Altaz($moonCoor{ra}, $moonCoor{dec}, $TDT, $observerlat, $lmst);
}
#-- Age of Moon in radians since New Moon (0) - Full Moon (pi)
- $moonCoor{age} = Astro_mod2Pi($l3-$sunlon);
+ $moonCoor{age} = _mod2Pi($l3-$sunlon);
$moonCoor{phasen} = 0.5*(1-cos($moonCoor{age})); # Moon phase numerical, 0-1
my $mainPhase = 1./29.53*360*$DEG; # show 'Newmoon, 'Quarter' for +/-1 day around the actual event
- my $p = Astro_mod($moonCoor{age}, 90.*$DEG);
+ my $p = _mod($moonCoor{age}, 90.*$DEG);
if ($p < $mainPhase || $p > 90*$DEG-$mainPhase){
$p = 2*floor($moonCoor{age} / (90.*$DEG)+0.5);
}else{
@@ -716,11 +1426,11 @@ sub Astro_MoonPosition($$$$$$$){
########################################################################################################
#
-# Astro_Refraction - Input true altitude in radians, Output: increase in altitude in degrees
+# Refraction - Input true altitude in radians, Output: increase in altitude in degrees
#
########################################################################################################
-sub Astro_Refraction($){
+sub Refraction($){
my ($alt) = @_;
my $altdeg = $alt*$RAD;
if ($altdeg<-2 || $altdeg>=90){
@@ -761,7 +1471,7 @@ sub Astro_Refraction($){
########################################################################################################
#
-# Astro_GMSTRiseSet - returns Greenwich sidereal time (hours) of time of rise
+# GMSTRiseSet - returns Greenwich sidereal time (hours) of time of rise
# and set of object with coordinates ra/dec
# at geographic position lon/lat (all values in radians)
# Correction for refraction and semi-diameter/parallax of body is taken care of in function RiseSet
@@ -769,16 +1479,16 @@ sub Astro_Refraction($){
#
########################################################################################################
-sub Astro_GMSTRiseSet($$$$$){
+sub GMSTRiseSet($$$$$){
my ($ra, $dec, $lon, $lat, $h) = @_;
$h = (defined($h)) ? $h : 0.0; # set default value
- #Log 1,"-------------------> Called Astro_GMSTRiseSet with $ra $dec $lon $lat $h";
+ #Log 1,"-------------------> Called GMSTRiseSet with $ra $dec $lon $lat $h";
# my $tagbogen = acos(-tan(lat)*tan(coor.dec)); // simple formula if twilight is not required
my $tagbarg = (sin($h) - sin($lat)*sin($dec)) / (cos($lat)*cos($dec));
if( ($tagbarg > 1.000000) || ($tagbarg < -1.000000) ){
- Log 5,"[Astro_GMSTRiseSet] Parameters $ra $dec $lon $lat $h give complex angle";
+ Log 5,"[FHEM::Astro::GMSTRiseSet] Parameters $ra $dec $lon $lat $h give complex angle";
return( ("---","---","---") );
};
my $tagbogen = acos($tagbarg);
@@ -787,34 +1497,34 @@ sub Astro_GMSTRiseSet($$$$$){
my $rise = 24.+$RAD/15*(-$tagbogen+$ra-$lon); # calculate GMST of rise of object
my $set = $RAD/15*(+$tagbogen+$ra-$lon); # calculate GMST of set of object
- #--Using the modulo function Astro_mod, the day number goes missing. This may get a problem for the moon
- $transit = Astro_mod($transit, 24);
- $rise = Astro_mod($rise, 24);
- $set = Astro_mod($set, 24);
+ #--Using the modulo function mod, the day number goes missing. This may get a problem for the moon
+ $transit = _mod($transit, 24);
+ $rise = _mod($rise, 24);
+ $set = _mod($set, 24);
return( ($transit, $rise, $set) );
}
########################################################################################################
#
-# Astro_InterpolateGMST - Find GMST of rise/set of object from the two calculated
+# InterpolateGMST - Find GMST of rise/set of object from the two calculated
# (start)points (day 1 and 2) and at midnight UT(0)
#
########################################################################################################
-sub Astro_InterpolateGMST($$$$){
+sub InterpolateGMST($$$$){
my ($gmst0, $gmst1, $gmst2, $timefactor) = @_;
return( ($timefactor*24.07*$gmst1- $gmst0*($gmst2-$gmst1)) / ($timefactor*24.07+$gmst1-$gmst2) );
}
########################################################################################################
#
-# Astro_RiseSet
+# RiseSet
# // JD is the Julian Date of 0h UTC time (midnight)
#
########################################################################################################
-sub Astro_RiseSet($$$$$$$$$$$){
+sub RiseSet($$$$$$$$$$$){
my ($jd0UT, $diameter, $parallax, $ra1, $dec1, $ra2, $dec2, $lon, $lat, $timeinterval, $altip) = @_;
#--altitude of sun center: semi-diameter, horizontal parallax and (standard) refraction of 34'
@@ -822,8 +1532,8 @@ sub Astro_RiseSet($$$$$$$$$$$){
my $alt = (!defined($altip)) ? 0.5*$diameter-$parallax+34./60*$DEG : 0.;
my $altitude = (!defined($altip)) ? 0. : $altip;
- my ($transit1, $rise1, $set1) = Astro_GMSTRiseSet($ra1, $dec1, $lon, $lat, $altitude);
- my ($transit2, $rise2, $set2) = Astro_GMSTRiseSet($ra2, $dec2, $lon, $lat, $altitude);
+ my ($transit1, $rise1, $set1) = GMSTRiseSet($ra1, $dec1, $lon, $lat, $altitude);
+ my ($transit2, $rise2, $set2) = GMSTRiseSet($ra2, $dec2, $lon, $lat, $altitude);
#-- complex angle
if( ($transit1 eq "---") || ($transit2 eq "---") ){
@@ -838,7 +1548,7 @@ sub Astro_RiseSet($$$$$$$$$$$){
$set2 += 24
if ($set1 > $set2 && abs($set1-$set2)>18);
- my $T0 = Astro_GMST($jd0UT);
+ my $T0 = GMST($jd0UT);
# my $T02 = T0-zone*1.002738; // Greenwich sidereal time at 0h time zone (zone: hours)
#-- Greenwich sidereal time for 0h at selected longitude
my $T02 = $T0-$lon*$RAD/15*1.002738;
@@ -863,16 +1573,16 @@ sub Astro_RiseSet($$$$$$$$$$$){
my $y = asin(sin($alt)/sin($psi));
my $dt = 240*$RAD*$y/cos($decMean)/3600; # time correction due to refraction, parallax
- my $transit = Astro_GMST2UT( $jd0UT, Astro_InterpolateGMST( $T0, $transit1, $transit2, $timeinterval) );
- my $rise = Astro_GMST2UT( $jd0UT, Astro_InterpolateGMST( $T0, $rise1, $rise2, $timeinterval) - $dt );
- my $set = Astro_GMST2UT( $jd0UT, Astro_InterpolateGMST( $T0, $set1, $set2, $timeinterval) + $dt );
+ my $transit = GMST2UT( $jd0UT, InterpolateGMST( $T0, $transit1, $transit2, $timeinterval) );
+ my $rise = GMST2UT( $jd0UT, InterpolateGMST( $T0, $rise1, $rise2, $timeinterval) - $dt );
+ my $set = GMST2UT( $jd0UT, InterpolateGMST( $T0, $set1, $set2, $timeinterval) + $dt );
return( ($transit,$rise,$set) );
}
########################################################################################################
#
-# Astro_SunRise - Find (local) time of sunrise and sunset, and twilights
+# SunRise - Find (local) time of sunrise and sunset, and twilights
# JD is the Julian Date of 0h local time (midnight)
# Accurate to about 1-2 minutes
# recursive: 1 - calculate rise/set in UTC in a second run
@@ -881,22 +1591,22 @@ sub Astro_RiseSet($$$$$$$$$$$){
#
########################################################################################################
-sub Astro_SunRise($$$$$$){
- my ($JD, $deltaT, $lon, $lat, $zone, $recursive) = @_;
+sub SunRise($$$$$$$$){
+ my ($JD, $deltaT, $lon, $lat, $zone, $horM, $horE, $recursive) = @_;
my $jd0UT = floor($JD-0.5)+0.5; # JD at 0 hours UT
#-- calculations for noon
- my $sunCoor1 = Astro_SunPosition($jd0UT+ $deltaT/24./3600.,undef,undef);
+ my $sunCoor1 = SunPosition($jd0UT+ $deltaT/24./3600.,undef,undef);
#-- calculations for next day's UTC midnight
- my $sunCoor2 = Astro_SunPosition($jd0UT+1.+$deltaT/24./3600.,undef,undef);
+ my $sunCoor2 = SunPosition($jd0UT+1.+$deltaT/24./3600.,undef,undef);
#-- rise/set time in UTC
- my ($transit,$rise,$set) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ my ($transit,$rise,$set) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
$sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1,undef);
if( $transit eq "---" ){
- Log 3,"[Astro_SunRise] no solution possible - maybe the sun never sets ?";
+ Log 3,"[FHEM::Astro::SunRise] no solution possible - maybe the sun never sets ?";
return( ($transit,$rise,$set) );
}
@@ -906,7 +1616,7 @@ sub Astro_SunRise($$$$$$){
if ($zone>0) {
#rise time was yesterday local time -> calculate rise time for next UTC day
if ($rise >=24-$zone || $transit>=24-$zone || $set>=24-$zone) {
- ($transittemp,$risetemp,$settemp) = Astro_SunRise($JD+1, $deltaT, $lon, $lat, $zone, 1);
+ ($transittemp,$risetemp,$settemp) = SunRise($JD+1, $deltaT, $lon, $lat, $zone, $horM, $horE, 1);
$transit = $transittemp
if ($transit>=24-$zone);
$rise = $risetemp
@@ -917,76 +1627,82 @@ sub Astro_SunRise($$$$$$){
}elsif ($zone<0) {
#rise time was yesterday local time -> calculate rise time for previous UTC day
if ($rise<-$zone || $transit<-zone || $set<-zone) {
- ($transittemp,$risetemp,$settemp) = Astro_SunRise($JD-1, $deltaT, $lon, $lat, $zone, 1);
- $rise = $risetemp
- if ($rise<-$zone);
+ ($transittemp,$risetemp,$settemp) = SunRise($JD-1, $deltaT, $lon, $lat, $zone, $horM, $horE, 1);
$transit = $transittemp
if ($transit<-$zone);
+ $rise = $risetemp
+ if ($rise<-$zone);
$set = $settemp
if ($set <-$zone);
}
}
- $transit = Astro_mod($transit+$zone, 24.);
- $rise = Astro_mod($rise +$zone, 24.);
- $set = Astro_mod($set +$zone, 24.);
+ $transit = _mod($transit+$zone, 24.);
+ $rise = _mod($rise +$zone, 24.);
+ $set = _mod($set +$zone, 24.);
#-- Twilight calculation
#-- civil twilight time in UTC.
my $CivilTwilightMorning;
my $CivilTwilightEvening;
- ($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ ($transittemp,$risetemp,$settemp) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
$sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -6.*$DEG);
if( $transittemp eq "---" ){
- Log 4,"[Astro_SunRise] no solution possible for civil twilight - maybe the sun never sets below -6 degrees?";
+ Log 4,"[FHEM::Astro::SunRise] no solution possible for civil twilight - maybe the sun never sets below -6 degrees?";
$CivilTwilightMorning = "---";
$CivilTwilightEvening = "---";
}else{
- $CivilTwilightMorning = Astro_mod($risetemp +$zone, 24.);
- $CivilTwilightEvening = Astro_mod($settemp +$zone, 24.);
+ $CivilTwilightMorning = _mod($risetemp +$zone, 24.);
+ $CivilTwilightEvening = _mod($settemp +$zone, 24.);
}
#-- nautical twilight time in UTC.
my $NauticTwilightMorning;
my $NauticTwilightEvening;
- ($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ ($transittemp,$risetemp,$settemp) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
$sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -12.*$DEG);
if( $transittemp eq "---" ){
- Log 4,"[Astro_SunRise] no solution possible for nautical twilight - maybe the sun never sets below -12 degrees?";
+ Log 4,"[FHEM::Astro::SunRise] no solution possible for nautical twilight - maybe the sun never sets below -12 degrees?";
$NauticTwilightMorning = "---";
$NauticTwilightEvening = "---";
}else{
- $NauticTwilightMorning = Astro_mod($risetemp +$zone, 24.);
- $NauticTwilightEvening = Astro_mod($settemp +$zone, 24.);
+ $NauticTwilightMorning = _mod($risetemp +$zone, 24.);
+ $NauticTwilightEvening = _mod($settemp +$zone, 24.);
}
#-- astronomical twilight time in UTC.
my $AstroTwilightMorning;
my $AstroTwilightEvening;
- ($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ ($transittemp,$risetemp,$settemp) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
$sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, -18.*$DEG);
if( $transittemp eq "---" ){
- Log 4,"[Astro_SunRise] no solution possible for astronomical twilight - maybe the sun never sets below -18 degrees?";
+ Log 4,"[FHEM::Astro::SunRise] no solution possible for astronomical twilight - maybe the sun never sets below -18 degrees?";
$AstroTwilightMorning = "---";
$AstroTwilightEvening = "---";
}else{
- $AstroTwilightMorning = Astro_mod($risetemp +$zone, 24.);
- $AstroTwilightEvening = Astro_mod($settemp +$zone, 24.);
+ $AstroTwilightMorning = _mod($risetemp +$zone, 24.);
+ $AstroTwilightEvening = _mod($settemp +$zone, 24.);
}
#-- custom twilight time in UTC
my $CustomTwilightMorning;
my $CustomTwilightEvening;
- ($transittemp,$risetemp,$settemp) = Astro_RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
- $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, $Astro{ObsHor}*$DEG);
- if( $transittemp eq "---" ){
- Log 4,"[Astro_SunRise] no solution possible for custom twilight - maybe the sun never sets below ".$Astro{ObsHor}." degrees?";
+ ($transittemp,$risetemp,$settemp) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, $horM*$DEG);
+ if( $transittemp eq "---" ){
+ Log 4,"[FHEM::Astro::SunRise] no solution possible for custom morning twilight - maybe the sun never sets below ".$horM." degrees?";
$CustomTwilightMorning = "---";
+ }else{
+ $CustomTwilightMorning = _mod($risetemp +$zone, 24.);
+ }
+ ($transittemp,$risetemp,$settemp) = RiseSet($jd0UT, $sunCoor1->{diameter}, $sunCoor1->{parallax},
+ $sunCoor1->{ra}, $sunCoor1->{dec}, $sunCoor2->{ra}, $sunCoor2->{dec}, $lon, $lat, 1, $horE*$DEG);
+ if( $transittemp eq "---" ){
+ Log 4,"[FHEM::Astro::SunRise] no solution possible for custom evening twilight - maybe the sun never sets below ".$horE." degrees?";
$CustomTwilightEvening = "---";
}else{
- $CustomTwilightMorning = Astro_mod($risetemp +$zone, 24.);
- $CustomTwilightEvening = Astro_mod($settemp +$zone, 24.);
- }
+ $CustomTwilightEvening = _mod($settemp +$zone, 24.);
+ }
return( ($transit,$rise,$set,$CivilTwilightMorning,$CivilTwilightEvening,
$NauticTwilightMorning,$NauticTwilightEvening,$AstroTwilightMorning,$AstroTwilightEvening,$CustomTwilightMorning,$CustomTwilightEvening) );
@@ -997,7 +1713,7 @@ sub Astro_SunRise($$$$$$){
########################################################################################################
#
-# Astro_MoonRise - Find local time of moonrise and moonset
+# MoonRise - Find local time of moonrise and moonset
# JD is the Julian Date of 0h local time (midnight)
# Accurate to about 5 minutes or better
# recursive: 1 - calculate rise/set in UTC
@@ -1006,22 +1722,22 @@ sub Astro_SunRise($$$$$$){
#
########################################################################################################
-sub Astro_MoonRise($$$$$$$){
+sub MoonRise($$$$$$$){
my ($JD, $deltaT, $lon, $lat, $radius, $zone, $recursive) = @_;
my $timeinterval = 0.5;
my $jd0UT = floor($JD-0.5)+0.5; # JD at 0 hours UT
#-- calculations for noon
- my $sunCoor1 = Astro_SunPosition($jd0UT+ $deltaT/24./3600.,undef,undef);
- my $moonCoor1 = Astro_MoonPosition($sunCoor1->{lon}, $sunCoor1->{anomalyMean}, $jd0UT+ $deltaT/24./3600.,undef,undef,undef,undef);
+ my $sunCoor1 = SunPosition($jd0UT+ $deltaT/24./3600.,undef,undef);
+ my $moonCoor1 = MoonPosition($sunCoor1->{lon}, $sunCoor1->{anomalyMean}, $jd0UT+ $deltaT/24./3600.,undef,undef,undef,undef);
#-- calculations for next day's midnight
- my $sunCoor2 = Astro_SunPosition($jd0UT +$timeinterval + $deltaT/24./3600.,undef,undef);
- my $moonCoor2 = Astro_MoonPosition($sunCoor2->{lon}, $sunCoor2->{anomalyMean}, $jd0UT +$timeinterval + $deltaT/24./3600.,undef,undef,undef,undef);
+ my $sunCoor2 = SunPosition($jd0UT +$timeinterval + $deltaT/24./3600.,undef,undef);
+ my $moonCoor2 = MoonPosition($sunCoor2->{lon}, $sunCoor2->{anomalyMean}, $jd0UT +$timeinterval + $deltaT/24./3600.,undef,undef,undef,undef);
# rise/set time in UTC, time zone corrected later.
# Taking into account refraction, semi-diameter and parallax
- my ($transit,$rise,$set) = Astro_RiseSet($jd0UT, $moonCoor1->{diameter}, $moonCoor1->{parallax},
+ my ($transit,$rise,$set) = RiseSet($jd0UT, $moonCoor1->{diameter}, $moonCoor1->{parallax},
$moonCoor1->{ra}, $moonCoor1->{dec}, $moonCoor2->{ra}, $moonCoor2->{dec}, $lon, $lat, $timeinterval,undef);
my ($transittemp,$risetemp,$settemp);
my ($transitprev,$riseprev,$setprev);
@@ -1030,7 +1746,7 @@ sub Astro_MoonRise($$$$$$$){
if ( $recursive==0 ) {
if ($zone>0) {
# recursive call to MoonRise returns events in UTC
- ($transitprev,$riseprev,$setprev) = Astro_MoonRise($JD-1., $deltaT, $lon, $lat, $radius, $zone, 1);
+ ($transitprev,$riseprev,$setprev) = MoonRise($JD-1., $deltaT, $lon, $lat, $radius, $zone, 1);
if ($transit >= 24.-$zone || $transit < -$zone) { # transit time is tomorrow local time
if ($transitprev < 24.-$zone){
$transit = ""; # there is no moontransit today
@@ -1041,7 +1757,7 @@ sub Astro_MoonRise($$$$$$$){
if ($rise >= 24.-$zone || $rise < -$zone) { # rise time is tomorrow local time
if ($riseprev < 24.-$zone){
- $rise = ""; # there is no moontransit today
+ $rise = ""; # there is no moonrise today
}else{
$rise = $riseprev;
}
@@ -1049,7 +1765,7 @@ sub Astro_MoonRise($$$$$$$){
if ($set >= 24.-$zone || $set < -$zone) { # set time is tomorrow local time
if ($setprev < 24.-$zone){
- $set = ""; # there is no moontransit today
+ $set = ""; # there is no moonset today
}else{
$set = $setprev;
}
@@ -1057,7 +1773,15 @@ sub Astro_MoonRise($$$$$$$){
}elsif ($zone<0) { # rise/set time was tomorrow local time -> calculate rise time for previous UTC day
if ($rise<-$zone || $set<-$zone || $transit<-$zone) {
- ($transittemp,$risetemp,$settemp) = Astro_MoonRise($JD+1., $deltaT, $lon, $lat, $radius, $zone, 1);
+ ($transittemp,$risetemp,$settemp) = MoonRise($JD+1., $deltaT, $lon, $lat, $radius, $zone, 1);
+ if ($transit < -$zone){
+ if ($transittemp > -$zone){
+ $transit = ''; # there is no moontransit today
+ }else{
+ $transit = $transittemp;
+ }
+ }
+
if ($rise < -$zone) {
if ($risetemp > -$zone){
$rise = ''; # there is no moonrise today
@@ -1066,16 +1790,8 @@ sub Astro_MoonRise($$$$$$$){
}
}
- if ($transit < -zone){
- if ($transittemp > -zone){
- $transit = ''; # there is no moonset today
- }else{
- $transit = $transittemp;
- }
- }
-
- if ($set < -zone){
- if ($settemp > -zone){
+ if ($set < -$zone){
+ if ($settemp > -$zone){
$set = ''; # there is no moonset today
}else{
$set = $settemp;
@@ -1084,11 +1800,11 @@ sub Astro_MoonRise($$$$$$$){
}
}
#-- correct for time zone, if time is valid
- $transit = Astro_mod($transit +$zone, 24.)
+ $transit = _mod($transit +$zone, 24.)
if( $transit ne "");
- $rise = Astro_mod($rise +$zone, 24.)
+ $rise = _mod($rise +$zone, 24.)
if ($rise ne "");
- $set = Astro_mod($set +$zone, 24.)
+ $set = _mod($set +$zone, 24.)
if ($set ne "");
}
return( ($transit,$rise,$set) );
@@ -1096,27 +1812,103 @@ sub Astro_MoonRise($$$$$$$){
########################################################################################################
#
-# Astro_Compute - sequential calculation of properties
+# SetTime - update of the %Date hash for today
+#
+########################################################################################################
+
+sub SetTime (;$$$) {
+ my ( $time, $tz, $lc_time ) = @_;
+
+ #-- readjust locale
+ my $old_lctime = setlocale(LC_TIME);
+ setlocale(LC_TIME, $lc_time) if ($lc_time);
+ use locale ':not_characters';
+
+ #-- readjust timezone
+ local $ENV{TZ} = $tz if ($tz);
+ tzset();
+
+ $time = gettimeofday() unless ( defined($time) );
+
+ my ( $sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst ) =
+ localtime($time);
+ $year += 1900;
+ $month += 1;
+ $Date{timestamp} = $time;
+ $Date{timeday} = $hour + $min / 60. + $sec / 3600.;
+ $Date{year} = $year;
+ $Date{month} = $month;
+ $Date{day} = $day;
+ $Date{hour} = $hour;
+ $Date{min} = $min;
+ $Date{sec} = $sec;
+ $Date{isdst} = $isdst;
+ #-- broken on windows
+ #$Date{zonedelta} = (strftime "%z", localtime($time))/100;
+ $Date{zonedelta} = _tzoffset($time) / 100;
+ #-- half broken in windows
+ $Date{dayofyear} = 1 * strftime( "%j", localtime($time) );
+
+ $Date{wdayl} = strftime( "%A", localtime($time) );
+ $Date{wdays} = strftime( "%a", localtime($time) );
+ $Date{monthl} = strftime( "%B", localtime($time) );
+ $Date{months} = strftime( "%b", localtime($time) );
+ $Date{datetime} = strftime( "%c", localtime($time) );
+ $Date{week} = 1 * strftime( "%V", localtime($time) );
+ $Date{wday} = 1 * strftime( "%w", localtime($time) );
+ $Date{time} = strftime( "%X", localtime($time) );
+ $Date{date} = strftime( "%x", localtime($time) );
+ $Date{tz} = strftime( "%Z", localtime($time) );
+
+ delete $Date{tz} if (!$Date{tz} || $Date{tz} eq "" || $Date{tz} eq " ");
+
+ delete local $ENV{TZ};
+ tzset();
+
+ setlocale(LC_TIME, "");
+ setlocale(LC_TIME, $old_lctime);
+ no locale;
+
+ return (undef);
+}
+
+########################################################################################################
+#
+# Compute - sequential calculation of properties
#
########################################################################################################
-sub Astro_Compute($){
- my ($hash) = @_;
-
+sub Compute($;$){
+ my ($hash,$params) = @_;
+ undef %Astro;
my $name = $hash->{NAME};
-
- #-- readjust language
- my $lang = AttrVal("global","language","EN");
- if( $lang eq "DE"){
- $astro_tt = \%astro_transtable_DE;
- }else{
- $astro_tt = \%astro_transtable_EN;
- }
-
+ SetTime() if (scalar keys %Date == 0); # fill %Date if it is still empty after restart to avoid warnings
+
return undef if( !$init_done );
+ #-- readjust language
+ my $lang = uc(AttrVal($name,"language",AttrVal("global","language","EN")));
+ if( defined($params->{"language"}) &&
+ exists($transtable{uc($params->{"language"})})
+ ){
+ $tt = $transtable{uc($params->{"language"})};
+ }elsif( exists($transtable{uc($lang)}) ){
+ $tt = $transtable{uc($lang)};
+ }else{
+ $tt = $transtable{EN};
+ }
+
+ #-- readjust timezone
+ my $tz = AttrVal($name,"timezone",AttrVal("global","timezone",undef));
+ $tz = $params->{"timezone"}
+ if ( defined( $params->{"timezone"} ) );
+ local $ENV{TZ} = $tz if ($tz);
+ tzset();
+
#-- geodetic latitude and longitude of observer on WGS84
- if( defined($attr{$name}{"latitude"}) ){
+ if( defined($params->{"latitude"}) ){
+ $Astro{ObsLat} = $params->{"latitude"};
+ }elsif( defined($attr{$name}) && defined($attr{$name}{"latitude"}) ){
$Astro{ObsLat} = $attr{$name}{"latitude"};
}elsif( defined($attr{"global"}{"latitude"}) ){
$Astro{ObsLat} = $attr{"global"}{"latitude"};
@@ -1124,7 +1916,9 @@ sub Astro_Compute($){
$Astro{ObsLat} = 50.0;
Log3 $name,3,"[Astro] No latitude attribute set in global device, using 50.0°";
}
- if( defined($attr{$name}{"longitude"}) ){
+ if( defined($params->{"longitude"}) ){
+ $Astro{ObsLon} = $params->{"longitude"};
+ }elsif( defined($attr{$name}) && defined($attr{$name}{"longitude"}) ){
$Astro{ObsLon} = $attr{$name}{"longitude"};
}elsif( defined($attr{"global"}{"longitude"}) ){
$Astro{ObsLon} = $attr{"global"}{"longitude"};
@@ -1133,22 +1927,33 @@ sub Astro_Compute($){
Log3 $name,3,"[Astro] No longitude attribute set in global device, using 10.0°";
}
#-- altitude of observer in meters above WGS84 ellipsoid
- if( defined($attr{$name}{"altitude"}) ){
+ if( defined($params->{"altitude"}) ){
+ $Astro{ObsAlt} = $params->{"altitude"};
+ }elsif( defined($attr{$name}) && defined($attr{$name}{"altitude"}) ){
$Astro{ObsAlt} = $attr{$name}{"altitude"};
}elsif( defined($attr{"global"}{"altitude"}) ){
$Astro{ObsAlt} = $attr{"global"}{"altitude"};
}else{
$Astro{ObsAlt} = 0.0;
Log3 $name,3,"[Astro] No altitude attribute set in global device, using 0.0 m above sea level";
- }
+ }
#-- custom horizon of observer in degrees
- if( defined($attr{$name}{"horizon"}) ){
- $Astro{ObsHor} = $attr{$name}{"horizon"};
- }else{
- $Astro{ObsHor} = 0.0;
- Log3 $name,5,"[Astro] No horizon attribute defined, using 0.0°";
- }
-
+ if( defined($params->{"horizon"}) &&
+ $params->{"horizon"} =~ m/^([^:]+)(?::(.+))?$/
+ ){
+ $Astro{ObsHorMorning} = $1;
+ $Astro{ObsHorEvening} = defined($2) ? $2 : $1;
+ }elsif( defined($attr{$name}) && defined($attr{$name}{"horizon"}) &&
+ $attr{$name}{"horizon"} =~ m/^([^:]+)(?::(.+))?$/
+ ){
+ $Astro{ObsHorMorning} = $1;
+ $Astro{ObsHorEvening} = defined($2) ? $2 : $1;
+ } else {
+ $Astro{ObsHorMorning} = 0.0;
+ $Astro{ObsHorEvening} = 0.0;
+ Log3 $name,5,"[Astro] No horizon attribute defined, using 0.0° for morning and evening";
+ }
+
#-- internal variables converted to Radians and km
my $lat = $Astro{ObsLat}*$DEG;
my $lon = $Astro{ObsLon}*$DEG;
@@ -1159,114 +1964,221 @@ sub Astro_Compute($){
# return;
#}
- my $JD0 = Astro_CalcJD( $Date{day}, $Date{month}, $Date{year} );
+ my $JD0 = CalcJD( $Date{day}, $Date{month}, $Date{year} );
my $JD = $JD0 + ( $Date{hour} - $Date{zonedelta} + $Date{min}/60. + $Date{sec}/3600.)/24;
my $TDT = $JD + $deltaT/86400.0;
- $Astro{ObsJD} = Astro_round($JD,2);
+ $Astro{".ObsJD"} = $JD;
+ $Astro{ObsJD} = _round($JD,2);
- my $gmst = Astro_GMST($JD);
- $Astro{ObsGMST} = Astro_HHMMSS($gmst);
- my $lmst = Astro_GMST2LMST($gmst, $lon);
- $Astro{ObsLMST} = Astro_HHMMSS($lmst);
+ my $gmst = GMST($JD);
+ my $lmst = GMST2LMST($gmst, $lon);
+ $Astro{".ObsGMST"} = $gmst;
+ $Astro{".ObsLMST"} = $lmst;
+ $Astro{ObsGMST} = HHMMSS($gmst);
+ $Astro{ObsLMST} = HHMMSS($lmst);
#-- geocentric cartesian coordinates of observer
- my ($x,$y,$z,$radius) = Astro_Observer2EquCart($lon, $lat, $height, $gmst);
+ my ($x,$y,$z,$radius) = Observer2EquCart($lon, $lat, $height, $gmst);
#-- calculate data for the sun at given time
- my $sunCoor = Astro_SunPosition($TDT, $lat, $lmst*15.*$DEG);
- $Astro{SunLon} = Astro_round($sunCoor->{lon}*$RAD,1);
+ my $sunCoor = SunPosition($TDT, $lat, $lmst*15.*$DEG);
+ $Astro{SunLon} = _round($sunCoor->{lon}*$RAD,1);
#$Astro{SunLat} = $sunCoor->{lat}*$RAD;
- $Astro{SunRa} = Astro_round($sunCoor->{ra} *$RAD/15,1);
- $Astro{SunDec} = Astro_round($sunCoor->{dec}*$RAD,1);
- $Astro{SunAz} = Astro_round($sunCoor->{az} *$RAD,1);
- $Astro{SunAlt} = Astro_round($sunCoor->{alt}*$RAD + Astro_Refraction($sunCoor->{alt}),1); # including refraction WARNUNG => *RAD ???
- $Astro{SunSign} = $astro_tt->{$sunCoor->{sig}};
- $Astro{SunDiameter}=Astro_round($sunCoor->{diameter}*$RAD*60,1); #angular diameter in arc seconds
- $Astro{SunDistance}=Astro_round($sunCoor->{distance},0);
+ $Astro{".SunRa"}= _round($sunCoor->{ra} *$RAD/15,1);
+ $Astro{SunRa} = HHMM($Astro{".SunRa"});
+ $Astro{SunDec} = _round($sunCoor->{dec}*$RAD,1);
+ $Astro{SunAz} = _round($sunCoor->{az} *$RAD,1);
+ $Astro{SunAlt} = _round($sunCoor->{alt}*$RAD + Refraction($sunCoor->{alt}),1); # including refraction WARNUNG => *RAD ???
+ $Astro{SunSign} = $tt->{$sunCoor->{sig}};
+ $Astro{SunDiameter}=_round($sunCoor->{diameter}*$RAD*60,1); #angular diameter in arc seconds
+ $Astro{SunDistance}=_round($sunCoor->{distance},0);
#-- calculate distance from the observer (on the surface of earth) to the center of the sun
- my ($xs,$ys,$zs) = Astro_EquPolar2Cart($sunCoor->{ra}, $sunCoor->{dec}, $sunCoor->{distance});
- $Astro{SunDistanceObserver} = Astro_round(sqrt( ($xs-$x)**2 + ($ys-$y)**2 + ($zs-$z)**2 ),0);
+ my ($xs,$ys,$zs) = EquPolar2Cart($sunCoor->{ra}, $sunCoor->{dec}, $sunCoor->{distance});
+ $Astro{SunDistanceObserver} = _round(sqrt( ($xs-$x)**2 + ($ys-$y)**2 + ($zs-$z)**2 ),0);
my ($suntransit,$sunrise,$sunset,$CivilTwilightMorning,$CivilTwilightEvening,
$NauticTwilightMorning,$NauticTwilightEvening,$AstroTwilightMorning,$AstroTwilightEvening,$CustomTwilightMorning,$CustomTwilightEvening) =
- Astro_SunRise($JD0, $deltaT, $lon, $lat, $Date{zonedelta}, 0);
- $Astro{SunTransit} = Astro_HHMM($suntransit);
- $Astro{SunRise} = Astro_HHMM($sunrise);
- $Astro{SunSet} = Astro_HHMM($sunset);
- $Astro{CivilTwilightMorning} = Astro_HHMM($CivilTwilightMorning);
- $Astro{CivilTwilightEvening} = Astro_HHMM($CivilTwilightEvening);
- $Astro{NauticTwilightMorning} = Astro_HHMM($NauticTwilightMorning);
- $Astro{NauticTwilightEvening} = Astro_HHMM($NauticTwilightEvening);
- $Astro{AstroTwilightMorning} = Astro_HHMM($AstroTwilightMorning);
- $Astro{AstroTwilightEvening} = Astro_HHMM($AstroTwilightEvening);
- $Astro{CustomTwilightMorning} = Astro_HHMM($CustomTwilightMorning);
- $Astro{CustomTwilightEvening} = Astro_HHMM($CustomTwilightEvening);
+ SunRise($JD0, $deltaT, $lon, $lat, $Date{zonedelta}, $Astro{ObsHorMorning}, $Astro{ObsHorEvening}, 0);
+ $Astro{".SunTransit"} = $suntransit;
+ $Astro{".SunRise"} = $sunrise;
+ $Astro{".SunSet"} = $sunset;
+ $Astro{".CivilTwilightMorning"} = $CivilTwilightMorning;
+ $Astro{".CivilTwilightEvening"} = $CivilTwilightEvening;
+ $Astro{".NauticTwilightMorning"} = $NauticTwilightMorning;
+ $Astro{".NauticTwilightEvening"} = $NauticTwilightEvening;
+ $Astro{".AstroTwilightMorning"} = $AstroTwilightMorning;
+ $Astro{".AstroTwilightEvening"} = $AstroTwilightEvening;
+ $Astro{".CustomTwilightMorning"} = $CustomTwilightMorning;
+ $Astro{".CustomTwilightEvening"} = $CustomTwilightEvening;
+ $Astro{SunTransit} = HHMM($suntransit);
+ $Astro{SunRise} = HHMM($sunrise);
+ $Astro{SunSet} = HHMM($sunset);
+ $Astro{CivilTwilightMorning} = HHMM($CivilTwilightMorning);
+ $Astro{CivilTwilightEvening} = HHMM($CivilTwilightEvening);
+ $Astro{NauticTwilightMorning} = HHMM($NauticTwilightMorning);
+ $Astro{NauticTwilightEvening} = HHMM($NauticTwilightEvening);
+ $Astro{AstroTwilightMorning} = HHMM($AstroTwilightMorning);
+ $Astro{AstroTwilightEvening} = HHMM($AstroTwilightEvening);
+ $Astro{CustomTwilightMorning} = HHMM($CustomTwilightMorning);
+ $Astro{CustomTwilightEvening} = HHMM($CustomTwilightEvening);
+
+ #-- hours of day and night
+ my $hoursofsunlight;
+ my $hoursofnight;
+ if (
+ (!defined($sunset) && !defined($sunrise)) ||
+ ($sunset !~ m/^\d+/ && $sunrise !~ m/^\d+/)
+ ){
+ if ($Astro{SunAlt} > 0.) {
+ $hoursofsunlight = 24.;
+ $hoursofnight = 0.;
+ } else {
+ $hoursofsunlight = 0.;
+ $hoursofnight = 24.;
+ }
+ }
+ elsif (!defined($sunset) || $sunset !~ m/^\d+/) {
+ $hoursofsunlight = 24. - $sunrise;
+ $hoursofnight = 24. - $hoursofsunlight;
+ }
+ elsif (!defined($sunrise) || $sunrise !~ m/^\d+/) {
+ $hoursofsunlight = 24. - $sunset;
+ $hoursofnight = 24. - $hoursofsunlight;
+ } else {
+ my $ss = $sunset;
+ $ss += 24.
+ if ($sunrise > $sunset);
+ $hoursofsunlight = $ss - $sunrise;
+ $hoursofnight = 24. - $hoursofsunlight;
+ }
+ $Astro{".SunHrsVisible"} = $hoursofsunlight;
+ $Astro{".SunHrsInvisible"} = $hoursofnight;
+ $Astro{SunHrsVisible} = HHMM($hoursofsunlight);
+ $Astro{SunHrsInvisible} = HHMM($hoursofnight);
#-- calculate data for the moon at given time
- my $moonCoor = Astro_MoonPosition($sunCoor->{lon}, $sunCoor->{anomalyMean}, $TDT, $lon, $lat, $radius, $lmst*15.*$DEG);
- $Astro{MoonLon} = Astro_round($moonCoor->{lon}*$RAD,1);
- $Astro{MoonLat} = Astro_round($moonCoor->{lat}*$RAD,1);
- $Astro{MoonRa} = Astro_round($moonCoor->{ra} *$RAD/15.,1);
- $Astro{MoonDec} = Astro_round($moonCoor->{dec}*$RAD,1);
- $Astro{MoonAz} = Astro_round($moonCoor->{az} *$RAD,1);
- $Astro{MoonAlt} = Astro_round($moonCoor->{alt}*$RAD + Astro_Refraction($moonCoor->{alt}),1); # including refraction WARNUNG => *RAD ???
- $Astro{MoonSign} = $astro_tt->{$moonCoor->{sig}};
- $Astro{MoonDistance} = Astro_round($moonCoor->{distance},0);
- $Astro{MoonDiameter} = Astro_round($moonCoor->{diameter}*$RAD*60.,1); # angular diameter in arc seconds
- $Astro{MoonAge} = Astro_round($moonCoor->{age}*$RAD,1);
- $Astro{MoonPhaseN} = Astro_round($moonCoor->{phasen},2);
+ my $moonCoor = MoonPosition($sunCoor->{lon}, $sunCoor->{anomalyMean}, $TDT, $lon, $lat, $radius, $lmst*15.*$DEG);
+ $Astro{MoonLon} = _round($moonCoor->{lon}*$RAD,1);
+ $Astro{MoonLat} = _round($moonCoor->{lat}*$RAD,1);
+ $Astro{".MoonRa"} = _round($moonCoor->{ra} *$RAD/15.,1);
+ $Astro{MoonRa} = HHMM($Astro{".MoonRa"});
+ $Astro{MoonDec} = _round($moonCoor->{dec}*$RAD,1);
+ $Astro{MoonAz} = _round($moonCoor->{az} *$RAD,1);
+ $Astro{MoonAlt} = _round($moonCoor->{alt}*$RAD + Refraction($moonCoor->{alt}),1); # including refraction WARNUNG => *RAD ???
+ $Astro{MoonSign} = $tt->{$moonCoor->{sig}};
+ $Astro{MoonDistance} = _round($moonCoor->{distance},0);
+ $Astro{MoonDiameter} = _round($moonCoor->{diameter}*$RAD*60.,1); # angular diameter in arc seconds
+ $Astro{MoonAge} = _round($moonCoor->{age}*$RAD,1);
+ $Astro{MoonPhaseN} = _round($moonCoor->{phasen},2);
$Astro{MoonPhaseI} = $moonCoor->{phasei};
- $Astro{MoonPhaseS} = $astro_tt->{$moonCoor->{phases}};
+ $Astro{MoonPhaseS} = $tt->{$moonCoor->{phases}};
#-- calculate distance from the observer (on the surface of earth) to the center of the moon
- my ($xm,$ym,$zm) = Astro_EquPolar2Cart($moonCoor->{ra}, $moonCoor->{dec}, $moonCoor->{distance});
+ my ($xm,$ym,$zm) = EquPolar2Cart($moonCoor->{ra}, $moonCoor->{dec}, $moonCoor->{distance});
#Log 1," distance=".$moonCoor->{distance}." test=".sqrt( ($xm)**2 + ($ym)**2 + ($zm)**2 )." $xm $ym $zm";
#Log 1," distance=".$radius." test=".sqrt( ($x)**2 + ($y)**2 + ($z)**2 )." $x $y $z";
- $Astro{MoonDistanceObserver} = Astro_round(sqrt( ($xm-$x)**2 + ($ym-$y)**2 + ($zm-$z)**2 ),0);
-
- my ($moontransit,$moonrise,$moonset) = Astro_MoonRise($JD0, $deltaT, $lon, $lat, $radius, $Date{zonedelta}, 0);
- $Astro{MoonTransit} = Astro_HHMM($moontransit);
- $Astro{MoonRise} = Astro_HHMM($moonrise);
- $Astro{MoonSet} = Astro_HHMM($moonset);
+ $Astro{".MoonDistanceObserver"} = sqrt( ($xm-$x)**2 + ($ym-$y)**2 + ($zm-$z)**2 );
+ $Astro{MoonDistanceObserver} = _round($Astro{".MoonDistanceObserver"},0);
+ my ($moontransit,$moonrise,$moonset) = MoonRise($JD0, $deltaT, $lon, $lat, $radius, $Date{zonedelta}, 0);
+ $Astro{".MoonTransit"} = $moontransit;
+ $Astro{".MoonRise"} = $moonrise;
+ $Astro{".MoonSet"} = $moonset;
+ $Astro{MoonTransit} = HHMM($moontransit);
+ $Astro{MoonRise} = HHMM($moonrise);
+ $Astro{MoonSet} = HHMM($moonset);
+
+ #-- moon visiblity
+ my $moonvisible;
+ my $mooninvisible;
+ if (
+ (!defined($moonset) && !defined($moonrise)) ||
+ ($moonset !~ m/^\d+/ && $moonrise !~ m/^\d+/)
+ ){
+ if ($Astro{MoonAlt} >= 0.) {
+ $moonvisible = 24.;
+ $mooninvisible = 0.;
+ } else {
+ $moonvisible = 0.;
+ $mooninvisible = 24.;
+ }
+ }
+ elsif (!defined($moonset) || $moonset !~ m/^\d+/) {
+ $moonvisible = 24. - $moonrise;
+ $mooninvisible = 24. - $moonvisible;
+ }
+ elsif (!defined($moonrise) || $moonrise !~ m/^\d+/) {
+ $moonvisible = 24. - $moonset;
+ $mooninvisible = 24. - $moonvisible;
+ } else {
+ my $ss = $moonset;
+ $ss += 24.
+ if ($moonrise > $moonset);
+ $moonvisible = $ss - $moonrise;
+ $mooninvisible = 24. - $moonvisible;
+ }
+ $Astro{".MoonHrsVisible"} = $moonvisible;
+ $Astro{".MoonHrsInvisible"} = $mooninvisible;
+ $Astro{MoonHrsVisible} = HHMM($moonvisible);
+ $Astro{MoonHrsInvisible} = HHMM($mooninvisible);
+
#-- fix date
- $Astro{ObsDate}= sprintf("%02d.%02d.%04d",$Date{day},$Date{month},$Date{year});
- $Astro{ObsTime}= sprintf("%02d:%02d:%02d",$Date{hour},$Date{min},$Date{sec});
- $Astro{ObsTimezone}= $Date{zonedelta};
- $Astro{ObsIsDST}= $Date{isdst};
-
- #-- check season
- my $doj = $Date{dayofyear};
- $Astro{ObsDayofyear} = $doj;
-
+ $Astro{ObsDate} = $Date{date};
+ $Astro{ObsTime} = $Date{time};
+ $Astro{ObsTimezone} = $Date{zonedelta};
+ $Astro{ObsTimezoneS} = $Date{tz} if ( $Date{tz} );
+ $Astro{ObsDayofyear} = $Date{dayofyear};
+ $Astro{ObsIsDST} = $Date{isdst};
+ $Astro{".timestamp"} = $Date{timestamp};
+ $Astro{".timeday"} = $Date{timeday};
+ $Astro{".year"} = $Date{year};
+ $Astro{".month"} = $Date{month};
+ $Astro{".day"} = $Date{day};
+ $Astro{".hour"} = $Date{hour};
+ $Astro{".min"} = $Date{min};
+ $Astro{".sec"} = $Date{sec};
+ $Astro{".wdayl"} = $Date{wdayl};
+ $Astro{".wdays"} = $Date{wdays};
+ $Astro{".monthl"} = $Date{monthl};
+ $Astro{".months"} = $Date{months};
+ $Astro{".datetime"} = $Date{datetime};
+ $Astro{".week"} = $Date{week};
+ $Astro{".wday"} = $Date{wday};
+
+ #-- check astro season
+ my $doj = $Astro{ObsDayofyear};
+
for( my $i=0;$i<4;$i++){
my $key = $seasons[$i];
if( (($seasonn{$key}[0] < $seasonn{$key}[1]) && ($seasonn{$key}[0] <= $doj) && ($seasonn{$key}[1] >= $doj))
|| (($seasonn{$key}[0] > $seasonn{$key}[1]) && (($seasonn{$key}[0] <= $doj) || ($seasonn{$key}[1] >= $doj))) ){
- $Astro{ObsSeason} = $astro_tt->{$key};
+ $Astro{ObsSeason} = $tt->{$key};
$Astro{ObsSeasonN} = $i;
last;
}
}
-
+
+ delete local $ENV{TZ};
+ tzset();
+
return( undef );
};
-########################################################################################
+########################################################################################################
#
-# Astro_moonwidget - SVG picture of the moon
+# Moonwidget - SVG picture of the moon
#
-# Parameter hash = hash of the bus master a = argument array
+# Parameter arg = argument array
#
-########################################################################################
+########################################################################################################
-sub Astro_moonwidget($){
+sub Moonwidget($){
my ($arg) = @_;
my $name = $FW_webArgs{name};
- $name =~ s/'//g;
- my $hash = $defs{$name};
+ $name =~ s/'//g if ($name);
+ my $hash = $name && $name ne "" && defined($defs{$name}) ? $defs{$name} : ();
my $mooncolor = 'rgb(255,220,100)';
my $moonshadow = 'rgb(70,70,100)';
@@ -1281,8 +2193,8 @@ sub Astro_moonwidget($){
$FW_RETTYPE = "image/svg+xml";
$FW_RET="";
FW_pO '
Readings with prefix Sun refer to the sun, with prefix Moon refer to the moon.
- The suffixes for these readings are
+ The suffixes for these readings are:
Age = angle (in degrees) of body along its track
Az,Alt = azimuth and altitude angle (in degrees) of body above horizon
Dec,Ra = declination (in degrees) and right ascension (in HH:MM) of body position
+
HrsVisible,HrsInvisible = Hours of visiblity and invisiblity of the body
Lat,Lon = latitude and longituds (in degrees) of body position
Diameter = virtual diameter (in arc minutes) of body
Distance,DistanceObserver = distance (in km) of body to center of earth or to observer
@@ -1500,73 +2785,123 @@ sub Astro_Get($@) {
Readings with prefix Obs refer to the observer.
- In addition to some of the suffixes gives above, the following may occur
+ In addition to some of the suffixes gives above, the following may occur:
Date,Dayofyear = date
JD = Julian date
-
Season,SeasonN = String and numerical (0..3) value of season
-
Time,Timezone obvious meaning
+
Time,Timezone,TimezoneS = obvious meaning
IsDST = 1 if running on daylight savings time, 0 otherwise
GMST,LMST = Greenwich and Local Mean Sidereal Time (in HH:MM)
An SVG image of the current moon phase may be obtained under the link
- <ip address of fhem>/fhem/Astro_moonwidget?name='<device name>'
+ <ip address of fhem>/fhem/Astro_moonwidget?name='<device name>'.
Optional web parameters are [&size='<width>x<height>'][&mooncolor=<color>][&moonshadow=<color>]
Notes:
Calculations are only valid between the years 1900 and 2100
Attention: Timezone is taken from the local Perl settings, NOT automatically defined for a location
This module uses the global attribute language to determine its output data
- (default: EN=english). For German output set attr global language DE.
+ (default: EN=english). For German output, set attr global language DE.
+ If a local attribute on the device was set for language it will take precedence.
The time zone is determined automatically from the local settings of the
operating system. If geocordinates from a different time zone are used, the results are
not corrected automatically.
Some definitions determining the observer position are used
from the global device, i.e.
+
attr global longitude <value> attr global latitude <value>
- attr global altitude <value> (in m above sea level)
- These definitions are only used when there are no corresponding local attribute settings.
+ attr global altitude <value> (in m above sea level)
+
+ These definitions are only used when there are no corresponding local attribute settings on the device.
- It is not necessary to define an Astro device to use the data provided by this module
+ It is not necessary to define an Astro device to use the data provided by this module.
To use its data in any other module, you just need to put require "95_Astro.pm";
at the start of your own code, and then may call, for example, the function
- Astro_Get( SOME_HASH_REFERENCE,"dummy","text", "SunRise","2019-12-24");
- to acquire the sunrise on Christmas Eve 2019
+ to acquire the sunrise on Christmas Eve 2019. The hash reference may also be undefined or an existing device name of any type. Note that device attributes of the respective device will be respected as long as their name matches those mentioned for an Astro device.
+ attribute=value pairs may be added in text format to enforce
+ settings like language that would otherwise be defined by a real device.
+ You may also add parameters to customize your request:
+
+ set <name> update
+ trigger to recompute values immediately.
Get
Attention: Get-calls are NOT written into the readings of the device. Readings change only through periodic updates.
-
- get <name> json [<reading>]
- get <name> json [<reading>] YYYY-MM-DD
- get <name> json [<reading>] YYYY-MM-DD HH:MM:[SS]
- returns the complete set or an individual reading of astronomical data either for the current time, or for a day and time given in the argument.
-
- get <name> text [<reading>]
- get <name> text [<reading>] YYYY-MM-DD
- get <name> text [<reading>] YYYY-MM-DD HH:MM:[SS]
- returns the complete set or an individual reading of astronomical data either for the current time, or for a day and time given in the argument.
-
+
+ get <name> json [<reading>,[<reading>]] [-1|yesterday|+1|tomorrow]
+ get <name> json [<reading>,[<reading>]] YYYY-MM-DD [-1|yesterday|+1|tomorrow]
+ get <name> json [<reading>,[<reading>]] HH:MM[:SS] [-1|yesterday|+1|tomorrow]
+ get <name> json [<reading>,[<reading>]] YYYY-MM-DD HH:MM[:SS] [-1|yesterday|+1|tomorrow]
+ returns the complete set of an individual reading of astronomical data either for the current time, or for a day and time given in the argument. yesterday, tomorrow or any other integer number may be given at the end to get data relative to the given day and time.
+ Formatted values as described below may be generated in a subtree text by adding text=1 to the request.
+
+ get <name> text [<reading>,[<reading>]] [-1|yesterday|+1|tomorrow]
+ get <name> text [<reading>,[<reading>]] YYYY-MM-DD [-1|yesterday|+1|tomorrow]
+ get <name> text [<reading>,[<reading>]] HH:MM[:SS] [-1|yesterday|+1|tomorrow]
+ get <name> text [<reading>,[<reading>]] YYYY-MM-DD HH:MM[:SS] [-1|yesterday|+1|tomorrow]
+ returns the complete set of an individual reading of astronomical data either for the current time, or for a day and time given in the argument. yesterday, tomorrow or any other integer number may be given at the end to get data relative to the given day and time.
+ The return value may be formatted and/or labeled by adding one or more of the following key=value pairs to the request:
+
+
unit=1 = Will add a unit to numerical values. Depending on attribute lc_numeric, the decimal separator will be in regional format as well.
+
long=1 = A describtive label will be added to the value.
+
long=2 = Same as long=1 but Sun or Moon will be added as a prefix.
+
long=3 = Same as long=2 but <: > will be used as an additional separator.
+
+
get <name> version Display the version of the module
<interval>
- Update interval in seconds. The default is 3600 seconds, a value of 0 disables the automatic update.
-
Some definitions determining the observer position:
- attr <name> longitude <value>
- attr <name> latitude <value>
- attr <name> altitude <value> (in m above sea level)
- attr <name> horizon <value> custom horizon angle in degrees, default 0
- These definitions take precedence over global attribute settings.
-
+ Update interval in seconds. The default is 3600 seconds, a value of 0 disables the periodic update.
+
+ <language>
+ A language may be set to overwrite global attribute settings.
+
+ <lc_numeric>
+ Set regional settings to format numerical values in textual output. If not set, it will generate the locale based on the attribute language (if set).
+
+ <lc_time>
+ Set regional settings to format time related values in textual output. If not set, it will generate the locale based on the attribute language (if set).
+
+ <recomputeAt>
+ Enforce recomputing values at specific event times, independant from update interval. This attribute contains a list of one or many of the following values:
+
+
MoonRise,MoonSet,MoonTransit = for moon rise, set, and transit
+
NewDay = for 00:00:00 hours of the next calendar day
+
SunRise,SunSet,SunTransit = for sun rise, set, and transit
+
*TwilightEvening,*TwilightMorning = for the respective twilight stage begin
+
+
+ <timezone>
+ A timezone may be set to overwrite global and system settings. Format may depend on your local system implementation but is likely in the format similar to Europe/Berlin.
+
Some definitions determining the observer position:
+
+ attr <name> longitude <value>
+ attr <name> latitude <value>
+ attr <name> altitude <value> (in m above sea level)
+ attr <name> horizon <value> custom horizon angle in degrees, default 0. Different values for morning/evening may be set as <morning>:<evening>
+
+ These definitions take precedence over global attribute settings.
+
+ <disable>
+ When set, this will completely disable any device update.