Advertisement
TeraX

Homematic twilight.tcl

Mar 27th, 2013
386
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 12.52 KB | None | 0 0
  1. #!/bin/tclsh
  2. #Version 1.5 with wunderground patch and acosinus fix
  3. #param 0 = Breitengrad (noerdlich)
  4. #param 1 = Laengengrad (oestlich)
  5. #param 2 = kuenstlicher Horizont
  6. #param 3 = PLZ
  7. #
  8. # !!! Please change the API Key and City in Line 119 (and remove <>) !!!
  9. #
  10. #only run once, check if locking port 60 is opened
  11. if {[catch {socket -server unknown -myaddr 127.0.0.1 60} locksock]} then {
  12.   exit 0
  13. }
  14.  
  15. source /www/addons/lcd_msg/daemonize.tcl
  16.  
  17. load tclrega.so
  18.  
  19. proc showTime x {
  20.   if {$x && $x != 2000000000} then {
  21.     clock format $x -format "%H:%M:%S"
  22.   } else {
  23.     return "--:--:--"
  24.   }
  25. }
  26.  
  27. proc log x {
  28.   puts $::logfile "[showTime [clock seconds]]: $x"
  29.   flush $::logfile
  30. }
  31.  
  32. #define constants for the list access to make review easier
  33. set NIGHT 0
  34. set SR_ASTRONOMICAL 1
  35. set SR_NAUTICAL 2
  36. set SR_CIVIL 3
  37. set SR_SUNRISE 4
  38. set SR_INDOOR 5
  39. set SR_WEATHER 6
  40. set SS_WEATHER 7
  41. set SS_INDOOR 8
  42. set SS_SUNRISE 9
  43. set SS_CIVIL 10
  44. set SS_NAUTICAL 11
  45. set SS_ASTRONOMICAL 12
  46.  
  47. proc getTimeDiff {dayofyear} {
  48.   return [expr {-0.171*sin(0.0337 * $dayofyear + 0.465) - 0.1299*sin(0.01787 * $dayofyear - 0.168)}]
  49. }
  50.  
  51. #proc calcTwilightTimes {latitude longitude timezone dayofyear horizon sunrisevar sunsetvar} {
  52. #  upvar $sunrisevar sunrise
  53. #  upvar $sunsetvar sunset
  54. #
  55. #  if {[catch {
  56. #    set timediff [getTimeDiff $dayofyear]
  57. #    set declination [expr {0.4095 * sin(0.016906 * ($dayofyear - 80.086) ) }]
  58. #    set suntime [expr {12*acos((sin($horizon/57.29578) - sin($latitude/57.29578)*sin($declination)) / (cos($latitude/57.29578)*cos($declination)))/3.141592}]
  59. #    set sunrise [expr {[clock scan "0"] + round((12 - $timediff - $suntime - $longitude/15.0 + $timezone)*3600)}]
  60. #    set sunset  [expr {[clock scan "0"] + round((12 - $timediff + $suntime - $longitude/15.0 + $timezone)*3600)}]
  61. #  }] } then {
  62. #    set sunrise 0
  63. #    set sunset 2000000000
  64. #  }
  65. #}
  66.  
  67. proc calcTwilightTimes {latitude longitude timezone dayofyear horizon sunrisevar sunsetvar} {
  68.     upvar $sunrisevar sunrise
  69.     upvar $sunsetvar sunset
  70.  
  71.     set timediff [expr {-0.171*sin(0.0337 * $dayofyear + 0.465) - 0.1299*sin(0.01787 * $dayofyear - 0.168)}]
  72.     set declination [expr {0.4095 * sin(0.016906 * ($dayofyear - 80.086) ) }]
  73.  
  74.     set acosvar [expr ((sin($horizon/57.29578) - sin($latitude/57.29578)*sin($declination)) / (cos($latitude/57.29578)*cos($declination)))]
  75.         if {$acosvar <-1} {
  76.             set acosvar -1
  77.             log "Die Variable acosvar wurde auf -1 gesetzt, da ihr ursprünglicher Wert kleiner -1 war"
  78.             }
  79.            
  80.         if {$horizon == -18} {
  81.             log "Die Variable acosvar muss zwischen -1 und 1, liegen und ist momentan $acosvar"
  82.         }
  83.  
  84.     set suntime [expr {12*acos($acosvar)/3.141592}]
  85.     set sunrise [expr {[clock scan "0"] + round((12 - $timediff - $suntime - $longitude/15.0 + $timezone)*3600)}]
  86.     set sunset [expr {[clock scan "0"] + round((12 - $timediff + $suntime - $longitude/15.0 + $timezone)*3600)}]
  87. }
  88.  
  89. #proc getTwilightHorizon {logfile plz base_horizon} {
  90. #
  91. #  set url http://www.google.com/ig/api?weather=$plz-Germany&hl=de
  92. #  set twilightHorizon [expr {$base_horizon + 5.0}]
  93. #  catch {
  94. #    exec /usr/bin/wget -q -O /tmp/twilightweather.xml $url
  95. #    set f [open "/tmp/twilightweather.xml"]
  96. #    set a [read $f]
  97. #    close $f
  98. #    regexp "<current_conditions>(.*)</current_conditions>" $a dummy current
  99. #    foreach tag [split $current >] {
  100. #      regexp {<([^=>]*) data="([^=>"]*)"/} $tag dummy key value
  101. #        #" for editor
  102. #      set aCurrent($key) "$value"
  103. #    }
  104. #    ::log "current condition is \"$aCurrent(condition)\""
  105. #    file delete /tmp/twilightweather.xml
  106. #    switch $aCurrent(condition) {
  107. #      "Klar"              {set twilightHorizon [expr {$base_horizon + 0.2}]}
  108. #      "Meist sonnig"      {set twilightHorizon [expr {$base_horizon + 1.5}]}
  109. #      "Teils sonnig"      {set twilightHorizon [expr {$base_horizon + 3.0}]}
  110. #    }
  111. #  }
  112. #  ::log "twilight horizon set to $twilightHorizon"
  113. #  return $twilightHorizon
  114. #}
  115.     #
  116.     #modifizierter Teil w/ GOOGLE Wetterdienstabdankung. Jetzt wunderground.com
  117.     #
  118.     proc getTwilightHorizon {base_horizon} {
  119.     set url http://api.wunderground.com/api/<YOUR API KEY>/conditions/lang:DL/q/germany/<CITY>.xml
  120.     set twilightHorizon 5.0
  121.     exec /usr/bin/wget -q -O /tmp/twilightweather.xml $url
  122.     set f [open "/tmp/twilightweather.xml"]
  123.     set input [read $f]
  124.     close $f
  125.  
  126.     regexp "<current_observation>(.*?)</current_observation>" $input dummy current ; #get current observation
  127.     regexp "<weather>(.*?)</weather>" $current dummy weather ; #get current weather
  128.  
  129.     log "current condition is \"$weather\""
  130.     file delete /tmp/twilightweather.xml
  131.  
  132.     switch $weather {
  133.     "Klar" {set twilightHorizon [expr {$base_horizon + 0.2}]}
  134.     "Meist sonnig" {set twilightHorizon [expr {$base_horizon + 1.0}]}
  135.     "Teils sonnig" {set twilightHorizon [expr {$base_horizon + 1.7}]}
  136.     "Heiter" {set twilightHorizon [expr {$base_horizon + 1.8}]}
  137.     "Wolkig" {set twilightHorizon [expr {$base_horizon + 1.9}]}
  138.     "Meistens bewölkt" {set twilightHorizon [expr {$base_horizon + 2.0}]}
  139.     "Leichtes Nieseln" {set twilightHorizon [expr {$base_horizon + 4.0}]}
  140.     }
  141.     log "twilight horizon set to $twilightHorizon"
  142.     return $twilightHorizon
  143.     }
  144.  
  145. proc getDayOfYear {timestamp} {
  146.   set dayofyear [string trimleft [clock format $timestamp -format "%j"] "0"]
  147.   #subtract the fractional part to the next leap-year february 29th from the current day of the year
  148.   set dayofyear [expr {$dayofyear - ([clock format $timestamp -format "%Y"]%4)/4.0 - ($dayofyear)/365.25/4.0}]
  149.   return $dayofyear
  150. }
  151.  
  152. proc waitToTime {logfile destTime} {
  153.   set waittime [expr {1000*($destTime - [clock seconds])}]
  154.   if {$waittime > 0} then {
  155.     log "waiting [expr $waittime/1000] s until [clock format $destTime]"
  156.     #after is off of several seconds (exactly 1/1000?) after long waits, so wait 1% shorter and then wait again
  157.     after [expr { 990*($destTime - [clock seconds])}]
  158.     after [expr {1000*($destTime - [clock seconds])}]
  159.   } else {
  160.     log "not waiting [expr $waittime/1000] s until [clock format $destTime]"
  161.   }
  162. }
  163.  
  164. proc displayValues {} {
  165.   uplevel {
  166.     set display "s. folgende Tabelle vom [clock format [lindex $twilight_times 6] -format "%d.%m."]"
  167.     append display "</div><br/><table border=\"1\" bordercolor=\"#000000\" style=\"background-color:#5d6373\" width=\"100%\">\r\n"
  168.     append display "<tr><td><b>Daemmerung</b></td><td><b>Morgens</b></td><td><b>Abends</b></td></tr>\r\n"
  169.     for {set j 1} {$j <= 6} {incr j} {
  170.      
  171.       set insert "[lindex $twilight_descr $j]:"
  172.       if {$j == $i || $j == 12-$i} then {set insert "<b>$insert</b>"}
  173.       append display "<tr><td>$insert</td>"
  174.      
  175.       set insert "[showTime [lindex $twilight_times [expr $j-1]]]"
  176.       if {$j == $i} then {set insert "<b>$insert</b>"}
  177.       if {$j == 6 && !$srw_set} then {set insert "<i>$insert</i>"}
  178.       append display "<td>$insert</td>"
  179.      
  180.       set insert "[showTime [lindex $twilight_times [expr 12-$j]]]"
  181.       if {$j == 13-$i} then {set insert "<b>$insert</b>"}
  182.       if {$j == 6 && !$ssw_set} then {set insert "<i>$insert</i>"}
  183.       append display "<td>$insert</td></tr>\r\n"
  184.       #log "updating twilight time table: [showTime [lindex $twilight_times [expr $j-1]]] [showTime [lindex $twilight_times [expr 12-$j]]] [string map {: { }} [lindex $twilight_descr [expr $j-1]]]"
  185.     }
  186.     append display "</table></td>"
  187.     rega_script "dom.GetObject('Daemmerungszeiten').State('$display');"
  188.   }
  189. }
  190.  
  191. #
  192. # Main execution
  193. #
  194.  
  195. set latitude [lindex $argv 0]
  196. set longitude [lindex $argv 1]
  197. set indoor_horizon [lindex $argv 2]
  198. set plz [lindex $argv 3]
  199.  
  200. #some vars we need
  201. set horizon_values [list 0 -18 -12 -6 [expr {- 50.0 / 60.0}] $indoor_horizon [expr {$indoor_horizon + 5.1}]]
  202. set twilight_names [list night astronomical nautical civil standard indoor weather]
  203. set twilight_descr [list Nacht Astronom. Nautisch Buergerlich Standard Indoor Wetterabh.]
  204.  
  205. while {1} {
  206.   set timezone [expr {([clock scan "0 UTC"] - [clock scan "0"]) / 3600.0}]
  207.   set now [clock seconds]
  208.   set twilight_midnight [expr {[clock scan "0"] + round((0 - [getTimeDiff [getDayOfYear $now]] - $longitude/15.0 + $timezone)*3600)}]
  209.  
  210.   #get the day of the year as numeric value based on twilight midnight (time between midnight and twilight midnight belongs to day before)
  211.   set yesterday_offset 0
  212.   if {$now < $twilight_midnight} then {
  213.     #use time table from day before
  214.     set yesterday_offset 86400
  215.   }
  216.   set dayofyear [getDayOfYear [expr $now-$yesterday_offset]]
  217.  
  218.   catch {file delete "/tmp/twilight.[expr int($dayofyear)-3].log"}
  219.   set logfile [open "/tmp/twilight.[expr int($dayofyear)].log" w]
  220.   log "args: $argv"
  221.   if {$now < $twilight_midnight} then {log "twilight midnight not reached, using yesterdays time table"}
  222.   log "timezone: $timezone, twilight midnight: [showTime $twilight_midnight], dayofyear: $dayofyear"
  223.  
  224.   set twilight_times ""
  225.   for {set i 1} {$i <= 6} {incr i} {
  226.     calcTwilightTimes $latitude $longitude $timezone $dayofyear [lindex $horizon_values $i] sunrise_time sunset_time
  227.     if {$sunrise_time == 0} then {
  228.       log "no [lindex $twilight_names $i] twilight here and now"
  229.     } elseif {$i != 6} then {
  230.       log "calculated twilight times: sunrise [clock format $sunrise_time -format "%d., %H:%M:%S"], sunset [clock format $sunset_time -format "%d., %H:%M:%S"] for [lindex $twilight_names $i] ($i)"
  231.     }
  232.     #do not append weather sunrise
  233.     if {$i != 6} then {
  234.       lappend twilight_times [expr $sunrise_time-$yesterday_offset]
  235.     }
  236.     #append indoor sunrise again to replace weather sunrise
  237.     if {$i == 5} then {
  238.       lappend twilight_times [expr $sunrise_time-$yesterday_offset+1]
  239.     }
  240.     #always append sunset
  241.     lappend twilight_times [expr $sunset_time-$yesterday_offset]
  242.   }
  243.   set twilight_times [lsort $twilight_times]
  244.   log "calculated twilight times: sunrise [clock format [lindex $twilight_times 5] -format "%d., %H:%M:%S"], sunset [clock format [lindex $twilight_times 6] -format "%d., %H:%M:%S"] for [lindex $twilight_names 6] (6)"
  245.   set srw_set 0
  246.   set ssw_set 0
  247.   displayValues
  248.  
  249.   #in the following calculation, assume that the weather sunrise and sunset are always subsequently on the current dayofyear    
  250.   for {set i 0} {$i < 12} {incr i} {
  251.     set next_time [lindex $twilight_times $i]
  252.    
  253.     if {$i == 5 && [clock seconds] < [lindex $twilight_times 6]} then {
  254.       #sunrise weather
  255.       log "retrieving weather condition for sunrise"
  256.  #     calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $logfile $plz $indoor_horizon] sunrise_weather dummy
  257.       calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $indoor_horizon] sunrise_weather dummy
  258.       set next_time $sunrise_weather
  259.       set srw_set 1
  260.       set twilight_times [lreplace $twilight_times 5 5 $sunrise_weather]
  261.       displayValues
  262.       log "weather sunrise at [showTime $next_time]"
  263.     }
  264.     if {[clock seconds] < $next_time && $next_time != 2000000000} then {
  265.       log "current twilight state $i ([lindex $twilight_descr [expr {6-abs($i-6)}]]), sunlight state [expr {6-abs($i-6)}], next at [showTime $next_time]"
  266.       rega_script "dom.GetObject('Daemmerung').State('$i');"
  267.       rega_script "dom.GetObject('Tageslicht').State('[expr {6-abs($i-6)}]');"
  268.       displayValues
  269.       waitToTime $logfile $next_time
  270.     }
  271.     if {$i == 6 && [clock seconds] < [lindex $twilight_times 7]} then {
  272.       #sunset weather
  273.       log "retrieving weather condition for sunset"
  274.       #calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $logfile $plz $indoor_horizon] dummy sunset_weather
  275.       calcTwilightTimes $latitude $longitude $timezone $dayofyear [getTwilightHorizon $indoor_horizon] dummy sunset_weather
  276.       set next_time $sunset_weather
  277.       set ssw_set 1
  278.       set twilight_times [lreplace $twilight_times 6 6 $sunset_weather]
  279.       displayValues
  280.       log "weather sunset at [showTime $next_time]"
  281.       waitToTime $logfile $next_time
  282.     }
  283.   }
  284.   rega_script "dom.GetObject('Daemmerung').State('12');"
  285.   rega_script "dom.GetObject('Tageslicht').State('0');"
  286.   log "twilight cycle completed for day of year $dayofyear, waiting until twilight midnight for next run"
  287.   waitToTime $logfile [expr {$twilight_midnight + 86400 - $yesterday_offset}]
  288.   close $logfile
  289. }
  290.      
  291. if {[file exists /var/run/twilight.tcl.pid]} then {
  292.   catch {
  293.     set f [open /var/run/twilight.tcl.pid]
  294.     set filepid [read $f]
  295.     close $f
  296.     if {[pid] == $filepid} then {
  297.       file delete /var/run/twilight.tcl.pid
  298.     }
  299.   }
  300. }
  301. close $locksock
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement