mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 16:59:18 +00:00
Reformatted (in order to understand) and fixed the summer/winter bug
git-svn-id: https://svn.fhem.de/fhem/trunk@1658 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
6bfc78f19b
commit
fb0bded435
@ -10,56 +10,67 @@ use warnings;
|
||||
use POSIX;
|
||||
use HttpUtils;
|
||||
|
||||
sub dayofyear {
|
||||
my ($day1,$month,$year)=@_;
|
||||
my @cumul_d_in_m =
|
||||
(0,31,59,90,120,151,181,212,243,273,304,334,365);
|
||||
my $doy=$cumul_d_in_m[--$month]+$day1;
|
||||
return $doy if $month < 2;
|
||||
return $doy unless $year % 4 == 0;
|
||||
return ++$doy unless $year % 100 == 0;
|
||||
return $doy unless $year % 400 == 0;
|
||||
return ++$doy;
|
||||
sub Twilight_calc($$$$$$$);
|
||||
sub Twilight_getWeatherHorizon($);
|
||||
sub Twilight_GetUpdate($);
|
||||
sub Twilight_dayofyear($$$);
|
||||
sub Twilight_my_gmt_offset();
|
||||
sub Twilight_midnight_seconds();
|
||||
|
||||
sub
|
||||
Twilight_dayofyear($$$)
|
||||
{
|
||||
my ($day1,$month,$year)=@_;
|
||||
my @cumul_d_in_m = (0,31,59,90,120,151,181,212,243,273,304,334,365);
|
||||
my $doy=$cumul_d_in_m[--$month]+$day1;
|
||||
return $doy if $month < 2;
|
||||
return $doy unless $year % 4 == 0;
|
||||
return ++$doy unless $year % 100 == 0;
|
||||
return $doy unless $year % 400 == 0;
|
||||
return ++$doy;
|
||||
}
|
||||
|
||||
sub my_gmt_offset {
|
||||
# inspired by http://stackoverflow.com/questions/2143528/whats-the-best-way-to-get-the-utc-offset-in-perl
|
||||
# avoid use of any CPAN module and ensure system independent behavior
|
||||
my $t = time;
|
||||
my @a = localtime($t);
|
||||
my @b = gmtime($t);
|
||||
my $hh = $a[2] - $b[2];
|
||||
my $mm = $a[1] - $b[1];
|
||||
# in the unlikely event that localtime and gmtime are in different years
|
||||
if ($a[5]*366+$a[4]*31+$a[3] > $b[5]*366+$b[4]*31+$b[3]) {
|
||||
$hh += 24;
|
||||
} elsif ($a[5]*366+$a[4]*31+$a[3] < $b[5]*366+$b[4]*31+$b[3]) {
|
||||
$hh -= 24;
|
||||
}
|
||||
if ($hh < 0 && $mm > 0) {
|
||||
$hh++;
|
||||
$mm = 60-$mm;
|
||||
}
|
||||
return $hh+($mm/60);
|
||||
sub
|
||||
Twilight_my_gmt_offset()
|
||||
{
|
||||
# inspired by http://stackoverflow.com/questions/2143528/whats-the-best-way-to-get-the-utc-offset-in-perl
|
||||
# avoid use of any CPAN module and ensure system independent behavior
|
||||
|
||||
my $t = time;
|
||||
my @a = localtime($t);
|
||||
my @b = gmtime($t);
|
||||
my $hh = $a[2] - $b[2];
|
||||
my $mm = $a[1] - $b[1];
|
||||
# in the unlikely event that localtime and gmtime are in different years
|
||||
if ($a[5]*366+$a[4]*31+$a[3] > $b[5]*366+$b[4]*31+$b[3]) {
|
||||
$hh += 24;
|
||||
} elsif ($a[5]*366+$a[4]*31+$a[3] < $b[5]*366+$b[4]*31+$b[3]) {
|
||||
$hh -= 24;
|
||||
}
|
||||
if ($hh < 0 && $mm > 0) {
|
||||
$hh++;
|
||||
$mm = 60-$mm;
|
||||
}
|
||||
return $hh+($mm/60);
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub Twilight_Initialize($) {
|
||||
|
||||
sub
|
||||
Twilight_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
# Provider# $hash->{Clients} = undef;
|
||||
|
||||
# Consumer
|
||||
$hash->{DefFn} = "Twilight_Define";
|
||||
$hash->{UndefFn} = "Twilight_Undef";
|
||||
$hash->{GetFn} = "Twilight_Get";
|
||||
$hash->{AttrList}= "loglevel:0,1,2,3,4,5 event-on-update-reading event-on-change-reading";
|
||||
|
||||
$hash->{AttrList}= "loglevel:0,1,2,3,4,5 event-on-update-reading ".
|
||||
"event-on-change-reading";
|
||||
}
|
||||
|
||||
sub Twilight_Get($@) {
|
||||
|
||||
sub
|
||||
Twilight_Get($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
return "argument is missing" if(int(@a) != 2);
|
||||
|
||||
@ -78,8 +89,9 @@ sub Twilight_Get($@) {
|
||||
}
|
||||
|
||||
|
||||
sub Twilight_Define($$) {
|
||||
|
||||
sub
|
||||
Twilight_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
# define <name> Twilight <latitude> <longitude> [indoor_horizon [Weather_Position]]
|
||||
# define MyTwilight Twilight 48.47 11.92 Weather_Position
|
||||
@ -117,12 +129,13 @@ sub Twilight_Define($$) {
|
||||
$hash->{WEATHER} = $weather;
|
||||
$hash->{INDOOR_HORIZON} = $indoor_horizon;
|
||||
|
||||
Twilight_GetUpdate($hash);
|
||||
return undef;
|
||||
Twilight_GetUpdate($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub Twilight_Undef($$) {
|
||||
|
||||
sub
|
||||
Twilight_Undef($$)
|
||||
{
|
||||
my ($hash, $arg) = @_;
|
||||
|
||||
RemoveInternalTimer($hash);
|
||||
@ -130,166 +143,175 @@ sub Twilight_Undef($$) {
|
||||
}
|
||||
|
||||
|
||||
sub twilight_midnight_seconds() { my @time = localtime(); my $secs = ($time[2] * 3600) + ($time[1] * 60) + $time[0]; return $secs; }
|
||||
|
||||
|
||||
sub Twilight_GetUpdate{
|
||||
my ($hash) = @_;
|
||||
my @sunrise_set;
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
my $sunrise;
|
||||
my $sunset;
|
||||
my $latitude=$hash->{LATITUDE};
|
||||
my $longitude=$hash->{LONGITUDE};
|
||||
my $horizon=$hash->{HORIZON};
|
||||
my $now=time;
|
||||
my $midnight=twilight_midnight_seconds();
|
||||
my $midseconds=$now-$midnight;
|
||||
my $year=strftime("%Y",localtime);
|
||||
my $month=strftime("%m",localtime);
|
||||
my $day=strftime("%d",localtime);
|
||||
my $doy = dayofyear($day,$month,$year)+(($year%4)/4);
|
||||
$doy+=($doy/365.0)/4.0;
|
||||
my $timezone=my_gmt_offset();
|
||||
my $timediff=-0.171*sin(0.0337*$doy+0.465) - 0.1299*sin(0.01787 * $doy - 0.168);
|
||||
my $declination=0.4095*sin(0.016906*($doy-80.086));
|
||||
my $twilight_midnight=$now+(0-$timediff-$longitude/15+$timezone)*3600;
|
||||
my $yesterday_offset;
|
||||
if($now<$twilight_midnight){
|
||||
$yesterday_offset=86400;
|
||||
}else{
|
||||
$yesterday_offset=0;
|
||||
}
|
||||
$year=strftime("%Y",localtime($now-$yesterday_offset));
|
||||
$month=strftime("%m",localtime($now-$yesterday_offset));
|
||||
$day=strftime("%d",localtime($now-$yesterday_offset));
|
||||
$doy = dayofyear($day,$month,$year)+(($year%4)/4);
|
||||
|
||||
$sunrise_set[0]{SR_NAME}="sr_astro";
|
||||
$sunrise_set[0]{SS_NAME}="ss_astro";
|
||||
$sunrise_set[0]{DEGREE}=-18;
|
||||
$sunrise_set[1]{SR_NAME}="sr_naut";
|
||||
$sunrise_set[1]{SS_NAME}="ss_naut";
|
||||
$sunrise_set[1]{DEGREE}=-12;
|
||||
$sunrise_set[2]{SR_NAME}="sr_civil";
|
||||
$sunrise_set[2]{SS_NAME}="ss_civil";
|
||||
$sunrise_set[2]{DEGREE}=-6;
|
||||
$sunrise_set[3]{SR_NAME}="sr";
|
||||
$sunrise_set[3]{SS_NAME}="ss";
|
||||
$sunrise_set[3]{DEGREE}=0;
|
||||
$sunrise_set[4]{SR_NAME}="sr_indoor";
|
||||
$sunrise_set[4]{SS_NAME}="ss_indoor";
|
||||
$sunrise_set[4]{DEGREE}=$hash->{INDOOR_HORIZON};
|
||||
$sunrise_set[5]{SR_NAME}="sr_weather";
|
||||
$sunrise_set[5]{SS_NAME}="ss_weather";
|
||||
Twilight_getWeatherHorizon($hash);
|
||||
readingsUpdate($hash,"condition",$hash->{CONDITION});
|
||||
if($hash->{WEATHER_HORIZON}>(89-$hash->{LATITUDE}+$declination)){$hash->{WEATHER_HORIZON}=89-$hash->{LATITUDE}+$declination;}
|
||||
$sunrise_set[5]{DEGREE}=$hash->{WEATHER_HORIZON};
|
||||
|
||||
|
||||
for(my $i=0;$i<6;$i++){
|
||||
($sunrise_set[$i]{RISE},$sunrise_set[$i]{SET})=
|
||||
twilight_calc($latitude,$longitude,$sunrise_set[$i]{DEGREE},$declination,$timezone,$midseconds,$timediff);
|
||||
readingsUpdate($hash, $sunrise_set[$i]{SR_NAME},
|
||||
$sunrise_set[$i]{RISE} eq "0" ? "undefined" :
|
||||
strftime("%H:%M:%S",localtime($sunrise_set[$i]{RISE})));
|
||||
readingsUpdate($hash, $sunrise_set[$i]{SS_NAME},
|
||||
$sunrise_set[$i]{SET} eq "2000000000" ? "undefined" :
|
||||
strftime("%H:%M:%S",localtime($sunrise_set[$i]{SET})));
|
||||
}
|
||||
my $k=0;
|
||||
my $half="RISE";
|
||||
my $nexttime;
|
||||
my $licht;
|
||||
for(my $i=0;$i < 12;$i++){
|
||||
$nexttime=$sunrise_set[6-abs($i-6)-$k]{$half};
|
||||
if($nexttime > $now && $nexttime!=2000000000){
|
||||
readingsUpdate($hash,"light", 6-abs($i-6));
|
||||
if($i<6){
|
||||
readingsUpdate($hash,"nextEvent",$sunrise_set[6-abs($i-6)-$k]{SR_NAME});
|
||||
}else{
|
||||
readingsUpdate($hash,"nextEvent",$sunrise_set[6-abs($i-6)-$k]{SS_NAME});
|
||||
}
|
||||
readingsUpdate($hash,"nextEventTime",strftime("%H:%M:%S",localtime($nexttime)));
|
||||
if($i==5 || $i==6){
|
||||
$nexttime = ($nexttime-$now)/2;
|
||||
$nexttime=120 if($nexttime<120);
|
||||
$nexttime=900 if($nexttime>900);
|
||||
}else{
|
||||
$nexttime = $nexttime-$now+10;
|
||||
}
|
||||
if(!$hash->{LOCAL}) {
|
||||
InternalTimer(sprintf("%.0f",$now+$nexttime), "Twilight_GetUpdate", $hash, 0);
|
||||
readingsUpdate($hash,"nextUpdate",strftime("%H:%M:%S",localtime($now+$nexttime)));
|
||||
}
|
||||
$hash->{STATE}=$i;
|
||||
last;
|
||||
}
|
||||
|
||||
if ($i == 5){
|
||||
$k=1;
|
||||
$half="SET";
|
||||
}
|
||||
if($nexttime<$now && $i==11){
|
||||
if(!$hash->{LOCAL}) {
|
||||
InternalTimer($now+900, "Twilight_GetUpdate", $hash, 0);
|
||||
}
|
||||
readingsUpdate($hash,"light", 0);
|
||||
$hash->{STATE}=0;
|
||||
}
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
return 1;
|
||||
sub
|
||||
Twilight_midnight_seconds()
|
||||
{
|
||||
my @time = localtime();
|
||||
my $secs = ($time[2] * 3600) + ($time[1] * 60) + $time[0];
|
||||
return $secs;
|
||||
}
|
||||
|
||||
sub twilight_calc {
|
||||
my $latitude=shift;
|
||||
my $longitude=shift;
|
||||
my $horizon=shift;
|
||||
my $declination=shift;
|
||||
my $timezone=shift;
|
||||
my $midseconds=shift;
|
||||
my $timediff=shift;
|
||||
my $suntime=0;
|
||||
my $sunrise=0;
|
||||
my $sunset=0;
|
||||
eval {
|
||||
$suntime=12*acos((sin($horizon/57.29578)-sin($latitude/57.29578)*sin($declination))/(cos($latitude/57.29578)*cos($declination)))/3.141592 ;
|
||||
$sunrise=$midseconds+(12-$timediff-$suntime-$longitude/15+$timezone)*3600;
|
||||
$sunset=$midseconds+(12-$timediff+$suntime-$longitude/15+$timezone)*3600;
|
||||
};
|
||||
if($@){
|
||||
$sunrise=0;
|
||||
$sunset=2000000000;
|
||||
}
|
||||
$sunrise = 0 if($sunrise eq "nan");
|
||||
$sunset = 2000000000 if($sunset eq "nan");
|
||||
return $sunrise, $sunset;
|
||||
}
|
||||
|
||||
sub Twilight_getWeatherHorizon{
|
||||
my @a_current = (25,25,25,25,20,10,10,10,10,10,10,7,7,7,5,10,10,6,6,6,10,6,6,6,6,6,6,5,5,3,3,0,0,0,0,7,0,15,15,15,9,15,8,5,12,6,8,8);
|
||||
#condition codes are described in FHEM wiki and in the documentation of the yahoo weather API
|
||||
my $hash=shift;
|
||||
my $location=$hash->{WEATHER};
|
||||
my $xml = GetFileFromURL("http://weather.yahooapis.com/forecastrss?w=".$location."&u=c",4.0);
|
||||
my $current;
|
||||
if($xml=~/code="(.*)"(\ *)temp/){
|
||||
if(defined($1)){
|
||||
$current=$1;
|
||||
}else{
|
||||
$current=-1;
|
||||
sub
|
||||
Twilight_GetUpdate($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my @sunrise_set;
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
my $latitude = $hash->{LATITUDE};
|
||||
my $longitude = $hash->{LONGITUDE};
|
||||
my $horizon = $hash->{HORIZON};
|
||||
my $now = time();
|
||||
my $midnight = Twilight_midnight_seconds();
|
||||
my $midseconds = $now-$midnight;
|
||||
my $year = strftime("%Y",localtime);
|
||||
my $month = strftime("%m",localtime);
|
||||
my $day = strftime("%d",localtime);
|
||||
my $doy = Twilight_dayofyear($day,$month,$year)+(($year%4)/4);
|
||||
$doy+=($doy/365.0)/4.0;
|
||||
my $timezone=Twilight_my_gmt_offset();
|
||||
my $timediff=-0.171*sin(0.0337*$doy+0.465) -
|
||||
0.1299*sin(0.01787 * $doy - 0.168);
|
||||
my $declination=0.4095*sin(0.016906*($doy-80.086));
|
||||
my $twilight_midnight=$now+(0-$timediff-$longitude/15+$timezone)*3600;
|
||||
my $yesterday_offset;
|
||||
if($now<$twilight_midnight){
|
||||
$yesterday_offset=86400;
|
||||
}else{
|
||||
$yesterday_offset=0;
|
||||
}
|
||||
|
||||
Twilight_getWeatherHorizon($hash);
|
||||
readingsUpdate($hash,"condition",$hash->{CONDITION});
|
||||
if($hash->{WEATHER_HORIZON} > (89-$hash->{LATITUDE}+$declination) ){
|
||||
$hash->{WEATHER_HORIZON} = 89-$hash->{LATITUDE}+$declination;
|
||||
}
|
||||
|
||||
my @names = ("_astro:-18", "_naut:-12", "_civil:-6",
|
||||
":0", "_indoor:0", "_weather:0");
|
||||
for(my $cnt = 0; $cnt < 6; $cnt++) {
|
||||
my ($name, $deg) = split(":", $names[$cnt]);
|
||||
$sunrise_set[$cnt]{SR_NAME} = "sr$name";
|
||||
$sunrise_set[$cnt]{SS_NAME} = "ss$name";
|
||||
$sunrise_set[$cnt]{DEGREE} = $deg;
|
||||
}
|
||||
$sunrise_set[4]{DEGREE}=$hash->{INDOOR_HORIZON};
|
||||
$sunrise_set[5]{DEGREE}=$hash->{WEATHER_HORIZON};
|
||||
|
||||
for(my $i=0; $i<6; $i++) {
|
||||
($sunrise_set[$i]{RISE}, $sunrise_set[$i]{SET})=
|
||||
Twilight_calc($latitude, $longitude, $sunrise_set[$i]{DEGREE},
|
||||
$declination, $timezone, $midseconds, $timediff);
|
||||
readingsUpdate($hash, $sunrise_set[$i]{SR_NAME},
|
||||
$sunrise_set[$i]{RISE} eq "nan" ? "undefined" :
|
||||
strftime("%H:%M:%S",localtime($sunrise_set[$i]{RISE})));
|
||||
readingsUpdate($hash, $sunrise_set[$i]{SS_NAME},
|
||||
$sunrise_set[$i]{SET} eq "nan" ? "undefined" :
|
||||
strftime("%H:%M:%S",localtime($sunrise_set[$i]{SET})));
|
||||
}
|
||||
my $k=0;
|
||||
my $half="RISE";
|
||||
my $sname="SR_NAME";
|
||||
my $alarmOffset;
|
||||
|
||||
for(my $i=0; $i < 12; $i++) {
|
||||
my $nexttime=$sunrise_set[6-abs($i-6)-$k]{$half};
|
||||
if($nexttime ne "nan" && $nexttime > $now) {
|
||||
readingsUpdate($hash, "light", 6-abs($i-6));
|
||||
readingsUpdate($hash, "nextEvent",
|
||||
$sunrise_set[6-abs($i-6)-$k]{$sname});
|
||||
readingsUpdate($hash, "nextEventTime",
|
||||
strftime("%H:%M:%S",localtime($nexttime)));
|
||||
|
||||
if($i==5 || $i==6) { # Weather
|
||||
$alarmOffset = ($nexttime-$now)/2;
|
||||
$alarmOffset = 120 if($alarmOffset<120);
|
||||
$alarmOffset = 900 if($alarmOffset>900);
|
||||
|
||||
} else {
|
||||
$alarmOffset = $nexttime-$now+10;
|
||||
|
||||
}
|
||||
|
||||
$hash->{STATE}=$i;
|
||||
last;
|
||||
}
|
||||
if(($current>=0) && ($current <=47)) {
|
||||
$hash->{WEATHER_HORIZON}=$a_current[$current]+$hash->{INDOOR_HORIZON};
|
||||
$hash->{CONDITION}=$current;
|
||||
return 1;
|
||||
|
||||
if($i == 5){ # Afternoon/evening
|
||||
$k=1;
|
||||
$half="SET";
|
||||
$sname="SS_NAME";
|
||||
}
|
||||
}
|
||||
Log 1, "[TWILIGHT] No Weather location found at yahoo weather for location ID: $location";
|
||||
|
||||
if(!$alarmOffset) {
|
||||
$alarmOffset = 900;
|
||||
readingsUpdate($hash,"light", 0);
|
||||
$hash->{STATE}=0;
|
||||
}
|
||||
if(!$hash->{LOCAL}) {
|
||||
InternalTimer($now+$alarmOffset, "Twilight_GetUpdate", $hash, 0);
|
||||
readingsUpdate($hash,"nextUpdate",
|
||||
strftime("%H:%M:%S",localtime($now+$alarmOffset)));
|
||||
}
|
||||
|
||||
readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub
|
||||
Twilight_calc($$$$$$$)
|
||||
{
|
||||
my ($latitude, $longitude, $horizon, $declination,
|
||||
$timezone, $midseconds, $timediff) = @_;
|
||||
my $suntime=0;
|
||||
my $sunrise=0;
|
||||
my $sunset=0;
|
||||
eval {
|
||||
$suntime = 12*acos((sin($horizon/57.29578) -
|
||||
sin($latitude/57.29578) * sin($declination)) /
|
||||
(cos($latitude/57.29578)*cos($declination))) /
|
||||
3.141592 ;
|
||||
$sunrise = $midseconds +
|
||||
(12-$timediff -$suntime -$longitude/15+$timezone) *
|
||||
3600;
|
||||
$sunset = $midseconds +
|
||||
(12-$timediff +$suntime -$longitude/15+$timezone) *
|
||||
3600;
|
||||
};
|
||||
$sunrise = $sunset = "nan" if($@);
|
||||
return $sunrise, $sunset;
|
||||
}
|
||||
|
||||
sub
|
||||
Twilight_getWeatherHorizon($)
|
||||
{
|
||||
my $hash=shift;
|
||||
my @a_current = (25,25,25,25,20,10,10,10,10,10,10, 7,
|
||||
7, 7, 5,10,10, 6, 6, 6,10, 6 ,6, 6,
|
||||
6, 6, 6, 5, 5, 3, 3, 0, 0, 0, 0, 7,
|
||||
0,15,15,15, 9,15, 8, 5,12, 6, 8, 8);
|
||||
# condition codes are described in FHEM wiki and in the documentation of the
|
||||
# yahoo weather API
|
||||
my $location=$hash->{WEATHER};
|
||||
my $xml = GetFileFromURL("http://weather.yahooapis.com/forecastrss?w=".
|
||||
$location."&u=c",4.0);
|
||||
my $current;
|
||||
if($xml=~/code="(.*)"(\ *)temp/){
|
||||
if(defined($1)){
|
||||
$current=$1;
|
||||
}else{
|
||||
$current=-1;
|
||||
}
|
||||
if(($current>=0) && ($current <=47)) {
|
||||
$hash->{WEATHER_HORIZON}=$a_current[$current]+$hash->{INDOOR_HORIZON};
|
||||
$hash->{CONDITION}=$current;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Log 1, "[TWILIGHT] No Weather location found at yahoo weather ".
|
||||
"for location ID: $location";
|
||||
$hash->{WEATHER_HORIZON}="0";
|
||||
$hash->{CONDITION}="-1";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user