Thursday, August 10, 2017

(#28) That doggone total eclipse is gonna mess me up


It just dawned on me (pun soon to be intended) that the looming Total Eclipse is going to break one of my more useful web services for about an hour.  That web service is my "is it dark outside?" web service.


Sunrise, sunset...

In Home Automation, it's handy to know when the sun rises, when it sets and where we are at any given time between those two boundaries.  Here's my implementation in PHP:

<?php
 $aLatitude = htmlspecialchars($_GET["lat"]);
 $aLongitude = htmlspecialchars($_GET["lon"]);
 $aTimeZone = htmlspecialchars( (isset($_GET['tz'])) ? $_GET['tz'] : 'America/Denver' );

 //
 // uncomment one zenith setting: http://en.wikipedia.org/wiki/Twilight
 $zenith = 90+(50/60); // True sunrise/sunset
 //$zenith = 96;           // Civilian Twilight - Conventionally used to signify twilight
 //$zenith = 102;         // Nautical Twilight - the point at which the horizon stops being visible at sea.
 //$zenith = 108;         // Astronomical Twilight - the point when Sun stops being a source of any illumination.

 //
 // Good enough approximation at offset
 $tzOffset = $aLongitude * 24 / 360;

 //
 // But evidently, I need to deal with Daylight Saving Time myself
 if (date( 'I' )) {
    $tzOffset += 1;
 }


 $sunriseStr = date_sunrise( time( date_default_timezone_set( $aTimeZone )), SUNFUNCS_RET_STRING, floatval($aLatitude), floatval($aLongitude), $zenith, $tzOffset );
 $sunsetStr  = date_sunset(  time( date_default_timezone_set( $aTimeZone )), SUNFUNCS_RET_STRING, floatval($aLatitude), floatval($aLongitude), $zenith, $tzOffset );

 $isDark = FALSE;

 $date1 = DateTime::createFromFormat( 'H:i', date( 'H:i' ));
 $date2 = DateTime::createFromFormat('H:i', $sunriseStr );
 $date3 = DateTime::createFromFormat('H:i', $sunsetStr );

 if ($date1 < $date2 || $date1 > $date3)
 {
    $isDark = TRUE;
 }
 
 $result_json = array( 'sunrise' => $sunriseStr,
                       'sunset' => $sunsetStr, 
                       'currentDateTime' => $date1, 
                       'timezone' => $aTimeZone,
                       'inDST' => (date( 'I' ) ? '1' : '0'), 
                       'isDark' => ($isDark ? '1' : '0') );

 // headers to tell that result is JSON
 header('Content-type: application/json');

 // send the result now
 echo json_encode($result_json);
?>


It fits my needs. Pass in a Lat/Lon for the sunrise and sunset times at that location. Leave them off and it assumes you live near me.

It also returns the current date, time and timezone data for, you guessed it, me.




Invocation is pretty simple. Here's today's sunrise/sunset request for Seattle:

http://<yourwebserver:port>/<path>/sunrise.php?lat=47.6lon=-122.3

The result comes back as JSON:

 
   "sunrise":"05:48",
   "sunset":"20:21",
   "currentDateTime": 
      "date":"2017-08-10 09:29:00.000000",
      "timezone_type":3,
      "timezone":"America\/Denver"
   },
   "timezone":"America\/Pacfic",
   "inDST":"1",
   "isDark":"0"
}

Again - that currentDateTime object is for me.  Change it or remove it to fit your needs.  Once this webservice is in place, having other applications check to see whether it's dark outside or not is also pretty easy. A contrived python example:

import json
import urllib2

# My website needs authentication
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
use it instead of None.
top_level_url = "http://<yourserver>/<path>/sunrise.php?lat=40&lon=-105"
password_mgr.add_password(None, top_level_url, <usr>, <passwd>)

handler = urllib2.HTTPDigestAuthHandler(password_mgr)
opener = urllib2.build_opener(handler)
urllib2.install_opener(opener)

data = urllib2.urlopen(top_level_url)
json_payload = json.load(data)
isdark = json_payload['isDark']

# do something
if isdark == "1":
   print "It is dark - turn on the outside lights"
else:
   print "It is light (not dark) - turn off the outside lights"





No comments :

Post a Comment