From 714a52ddc45f0828a4c964ec3a6e0c5d88aaafe1 Mon Sep 17 00:00:00 2001
From: jpawlowski
Date: Wed, 10 Jul 2019 09:06:13 +0000
Subject: [PATCH] 95_Astro: v2.1.0: add alternative global functions to replace
SUNRISE_EL
git-svn-id: https://svn.fhem.de/fhem/trunk@19812 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 2 +
fhem/FHEM/95_Astro.pm | 214 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 208 insertions(+), 8 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index d72bf1e46..50ad34fea 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,7 @@
# 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.
+ - feature: 95_Astro: v2.1.0: add alternative global functions
+ to replace SUNRISE_EL
- feature: 98_WeekdayTimer now supports holiday2we entries
weekEnd and noWeekEnd
- bugfix: 71_YAMAHA_NP: fixed 'timerRepeat'
diff --git a/fhem/FHEM/95_Astro.pm b/fhem/FHEM/95_Astro.pm
index 8bd67034d..50498f147 100644
--- a/fhem/FHEM/95_Astro.pm
+++ b/fhem/FHEM/95_Astro.pm
@@ -702,6 +702,19 @@ BEGIN {
Initialize
)
);
+
+ # Export to main context with different name
+ no strict qw/refs/;
+ *{'main::asunrise_rel'} = *{ 'FHEM::Astro::SUNRISE_EL_sunrise_rel' };
+ *{'main::asunset_rel'} = *{ 'FHEM::Astro::SUNRISE_EL_sunset_rel' };
+ *{'main::asunrise_abs'} = *{ 'FHEM::Astro::SUNRISE_EL_sunrise_abs' };
+ *{'main::asunset_abs'} = *{ 'FHEM::Astro::SUNRISE_EL_sunset_abs' };
+ *{'main::asunrise'} = *{ 'FHEM::Astro::SUNRISE_EL_sunrise' };
+ *{'main::asunset'} = *{ 'FHEM::Astro::SUNRISE_EL_sunset' };
+ *{'main::aisday'} = *{ 'FHEM::Astro::SUNRISE_EL_isday' };
+ *{'main::asunrise_abs_dat'} = *{ 'FHEM::Astro::SUNRISE_EL_sunrise_abs_dat' };
+ *{'main::asunset_abs_dat'} = *{ 'FHEM::Astro::SUNRISE_EL_sunset_abs_dat' };
+ use strict qw/refs/;
}
_LoadOptionalPackages();
@@ -736,10 +749,11 @@ sub Initialize ($) {
.$readingFnAttributes;
$hash->{parseParams} = 1;
+ $hash->{NotifyOrderPrefix} = '45-'; # we are a data provider
$data{FWEXT}{"/Astro_moonwidget"}{FUNC} = "FHEM::Astro::Moonwidget";
$data{FWEXT}{"/Astro_moonwidget"}{FORKABLE} = 0;
-
+
return FHEM::Meta::InitMod( __FILE__, $hash );
}
@@ -755,10 +769,18 @@ sub Define ($@) {
my ($hash,$a,$h) = @_;
my $name = shift @$a;
my $type = shift @$a;
+ my $global = shift @$a;
return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
+ if ($global) {
+ return "$type global device $modules{$type}{global}{NAME} is already defined"
+ if ( defined( $modules{$type}{global} ) );
+ $modules{$type}{global} = $hash;
+ $hash->{SCOPE} = 'global';
+ }
+
$hash->{NOTIFYDEV} = "global";
$hash->{INTERVAL} = 3600;
readingsSingleUpdate( $hash, "state", "Initialized", $init_done );
@@ -789,6 +811,15 @@ sub Undef ($$) {
my $type = $hash->{TYPE};
RemoveInternalTimer($hash);
+
+ delete $modules{$type}{defptr}{$name};
+
+ if ( defined( $modules{$type}{global} )
+ && $modules{$type}{global}{NAME} eq $name )
+ {
+ delete $modules{$type}{global};
+ Debug "Yes";
+ }
return undef;
}
@@ -1083,6 +1114,169 @@ sub _LoadOptionalPackages {
};
}
+########################################################################################################
+#
+# subroutines for 99_SUNRISE_EL.pm compatibility layer
+#
+########################################################################################################
+
+sub SUNRISE_EL_sr($$$$$$) {
+ my ( $rise, $seconds, $isrel, $daycheck, $min, $max ) = @_;
+ SUNRISE_EL_sr_alt(
+ time(), $rise, $isrel, $daycheck,
+ 1, $main::defaultaltit, $seconds, $min,
+ $max
+ );
+}
+
+sub SUNRISE_EL_sr_alt($$$$$$$$$) {
+ my $nt=shift;
+ my $rise=shift;
+ my $isrel=shift;
+ my $daycheck=shift;
+ my $nextDay=shift;
+ my $altit = defined($_[0]) ? $_[0] : "";
+ my $hasalt = 0;
+ if(exists $main::alti{uc($altit)}) {
+ $hasalt = 1;
+ $altit=$main::alti{uc($altit)};
+ shift;
+ } elsif($altit =~ /HORIZON=([\-\+]*[0-9\.]+)/i) {
+ $hasalt = 1;
+ $altit=$1;
+ shift;
+ } else {
+ $altit=-6; #default
+ }
+ my($seconds, $min, $max)=@_;
+ my $needrise = ($rise || $daycheck) ? 1 : 0;
+ my $needset = (!$rise || $daycheck) ? 1 : 0;
+ $seconds = 0 if(!$seconds);
+
+ my $hash = defined( $modules{Astro}{global} ) ? $modules{Astro}{global} : ();
+ my $name = defined( $hash->{NAME} ) ? $hash->{NAME} : '';
+
+ ############################
+ # If set in global, use longitude/latitude
+ # from global, otherwise set Frankfurt/Germany as
+ # default
+ my $long = AttrVal( $name, "longitude", AttrVal( "global", "longitude", 10.0 ) );
+ my $lat = AttrVal( $name, "latitude", AttrVal( "global", "latitude", 50.0 ) );
+ $altit = AttrVal( $name, "horizon", AttrVal( "global", "horizon", -6. ) ) unless($hasalt);
+ Log3 $name ne '' ? $name : undef, $name ne '' ? 4 : 5,
+ "[FHEM::Astro::SUNRISE_EL] "
+ . ( $name ne '' ? "$name: " : '' )
+ . "Compute sunrise/sunset for latitude $lat , longitude $long , horizon $altit at "
+ . FmtDateTime($nt);
+
+ #-- readjust timezone
+ my $tz =
+ AttrVal( $name, "timezone", AttrVal( "global", "timezone", undef ) );
+ local $ENV{TZ} = $tz if ($tz);
+ tzset() if ( exists &{'tzset'} );
+
+ #my $nt = time;
+ my @lt = localtime($nt);
+ my $gmtoff = main::_calctz($nt,@lt); # in hour
+
+ my ($rt,$st) = _SUNRISE_EL_sr_alt($lat,$long,$altit,$needrise,$needset,$nt,$gmtoff);
+ my $sst = ($rise ? $rt : $st) + ($seconds/3600);
+
+ my $nh = $lt[2] + $lt[1]/60 + $lt[0]/3600; # Current hour since midnight
+ if($daycheck) {
+ if(defined($min) && defined($max)) { #Forum #43742
+ $min = main::hms2h($min); $max = main::hms2h($max);
+ if($min < $max) {
+ $rt = $min if($rt < $min);
+ $st = $max if($st > $max);
+ } else {
+ $rt = $max if($rt > $max);
+ $st = $min if($st < $min);
+ }
+ }
+ return 1 if($rt <= $nh && $nh <= $st);
+ return 0;
+ }
+
+ $sst = main::hms2h($min) if(defined($min) && (main::hms2h($min) > $sst));
+ $sst = main::hms2h($max) if(defined($max) && (main::hms2h($max) < $sst));
+
+ my $diff = 0;
+ if (($data{AT_RECOMPUTE} || # compute it for tommorow
+ int(($nh-$sst)*3600) >= 0) && $nextDay) { # if called a subsec earlier
+ $nt += 86400;
+ @lt = localtime($nt);
+ my $ngmtoff = main::_calctz($nt,@lt); # in hour
+ $diff = 24;
+
+ ($rt,$st) = _SUNRISE_EL_sr_alt($lat,$long,$altit,$needrise,$needset,$nt,$ngmtoff);
+ $sst = ($rise ? $rt : $st) + ($seconds/3600);
+
+ $sst = main::hms2h($min) if(defined($min) && (main::hms2h($min) > $sst));
+ $sst = main::hms2h($max) if(defined($max) && (main::hms2h($max) < $sst));
+ }
+
+ $sst += $diff if($isrel);
+ $sst -= $nh if($isrel == 1);
+
+ delete local $ENV{TZ};
+ tzset() if ( exists &{'tzset'} );
+
+ return main::h2hms_fmt($sst);
+}
+
+sub _SUNRISE_EL_sr_alt($$$$$$$) {
+ my ( $lat, $long, $altit, $needrise, $needset, $nt, $offset ) = @_;
+ my $hash =
+ defined( $modules{Astro}{global} ) ? $modules{Astro}{global} : ();
+ my $name = defined( $hash->{NAME} ) ? $hash->{NAME} : '';
+
+ my $horM = 0.0;
+ my $horE = 0.0;
+ if ( $altit =~ m/^([^:]+)(?::(.+))?$/ ) {
+ $horM = $1;
+ $horE = defined($2) ? $2 : $1;
+ }
+
+ my $tz =
+ AttrVal( $name, "timezone", AttrVal( "global", "timezone", undef ) );
+ SetTime( $nt, $tz );
+ my $JD0 = Date2JD( $Date{day}, $Date{month}, $Date{year} );
+
+ my (
+ $suntransit, $sunrise,
+ $sunset, $CivilTwilightMorning,
+ $CivilTwilightEvening, $NauticTwilightMorning,
+ $NauticTwilightEvening, $AstroTwilightMorning,
+ $AstroTwilightEvening, $CustomTwilightMorning,
+ $CustomTwilightEvening
+ )
+ = SunRise(
+ $JD0, $deltaT,
+ $long * $DEG,
+ $lat * $DEG,
+ $Date{zonedelta}, $horM, $horE, 0
+ );
+
+ return ( $needrise ? $CustomTwilightMorning : undef ),
+ ( $needset ? $CustomTwilightEvening : undef );
+}
+
+sub SUNRISE_EL_sunrise_rel(@) { return SUNRISE_EL_sr_alt(time(),1,1,0,1,shift,shift,shift,shift); }
+sub SUNRISE_EL_sunset_rel (@) { return SUNRISE_EL_sr_alt(time(),0,1,0,1,shift,shift,shift,shift); }
+sub SUNRISE_EL_sunrise_abs(@) { return SUNRISE_EL_sr_alt(time(),1,0,0,0,shift,shift,shift,shift); }
+sub SUNRISE_EL_sunset_abs (@) { return SUNRISE_EL_sr_alt(time(),0,0,0,0,shift,shift,shift,shift); }
+sub SUNRISE_EL_sunrise (@) { return SUNRISE_EL_sr_alt(time(),1,2,0,1,shift,shift,shift,shift); }
+sub SUNRISE_EL_sunset (@) { return SUNRISE_EL_sr_alt(time(),0,2,0,1,shift,shift,shift,shift); }
+sub SUNRISE_EL_isday (@) { return SUNRISE_EL_sr_alt(time(),1,0,1,1,shift,shift,shift,shift); }
+
+sub SUNRISE_EL_sunrise_abs_dat(@) {
+ return SUNRISE_EL_sr_alt(main::sr_noon(shift),1,0,0,0,shift,shift,shift,shift);
+}
+sub SUNRISE_EL_sunset_abs_dat (@) {
+ return SUNRISE_EL_sr_alt(main::sr_noon(shift),0,0,0,0,shift,shift,shift,shift);
+}
+
########################################################################################################
#
# wrapper for Perl versions before 2018-06-09
@@ -1885,7 +2079,7 @@ sub SetTime (;$$$) {
#-- readjust timezone
local $ENV{TZ} = $tz if ($tz);
- tzset() if ( defined( *{'tzset'} ) );
+ tzset() if ( exists &{'tzset'} );
$time = gettimeofday() unless ( defined($time) );
@@ -1922,7 +2116,7 @@ sub SetTime (;$$$) {
delete $Date{tz} if (!$Date{tz} || $Date{tz} eq "" || $Date{tz} eq " ");
delete local $ENV{TZ};
- tzset() if ( defined( *{'tzset'} ) );
+ tzset() if ( exists &{'tzset'} );
setlocale(LC_TIME, "");
setlocale(LC_TIME, $old_lctime);
@@ -1963,7 +2157,7 @@ sub Compute($;$){
$tz = $params->{"timezone"}
if ( defined( $params->{"timezone"} ) );
local $ENV{TZ} = $tz if ($tz);
- tzset() if ( defined( *{'tzset'} ) );
+ tzset() if ( exists &{'tzset'} );
#-- geodetic latitude and longitude of observer on WGS84
if( defined($params->{"latitude"}) ){
@@ -2215,7 +2409,7 @@ sub Compute($;$){
$Astro{ObsSeasonN} = $seasonn;
delete local $ENV{TZ};
- tzset() if ( defined( *{'tzset'} ) );
+ tzset() if ( exists &{'tzset'} );
return( undef );
};
@@ -2840,8 +3034,10 @@ sub Get($@) {
Define
- define <name> Astro
-
Defines the Astro device (only one is needed per FHEM installation).
+ define <name> Astro [global]
+
Defines the Astro device (only one is needed per FHEM installation).
+
+ Optional parameter 'global' will mark this device for global configuration options, see SUNRISE_EL compatibility mode below for details.
Readings with prefix Sun refer to the sun, with prefix Moon refer to the moon.
The suffixes for these readings are:
@@ -2902,6 +3098,8 @@ sub Get($@) {
Astro_Get( SOME_HASH_REFERENCE, ["dummy","text"], {html=>1} );
Astro_Get( SOME_HASH_REFERENCE, ["dummy","text","SunRise,SunSet,SunAz,SunDistanceObserver"], {html=>1, long=>2} );
+ Functions that can replace those from SUNRISE_EL are available under the same name and adding a as a prefix in front of it (for example, use asunrise()
instead of sunrise()
). A single Astro device can act as a global configuration device for such functions if it was created using the global define parameter. If you don't want to create any Astro device at all, you may put LoadModule("Astro");
into your 99_myUtils.pm to only load the SUNRISE_EL replacement functions.
+
Set
@@ -2997,7 +3195,7 @@ sub Get($@) {
=end html_DE
=for :application/json;q=META.json 95_Astro.pm
{
- "version": "v2.0.3",
+ "version": "v2.1.0",
"author": [
"Prof. Dr. Peter A. Henning <>",
"Julian Pawlowski <>",