diff options
-rwxr-xr-x | blue.py | 159 |
1 files changed, 148 insertions, 11 deletions
@@ -8,27 +8,34 @@ import solar_python as sol loc = None stop_date = None human = False +unix = False +local = False noon = False +night = False blue = False gold = False unblue = False ungold = False morning = [] evening = [] -deriv = [] +dderiv = [] +nderiv = [] +res = '1s' ## Parse command line argv0 = sys.argv[0] if len(sys.argv) > 0 else 'blue' def usage(): - opts = '[-e elev]* [-m elev]* [-d delev]* [-l lat:lon | -l loc] [-s year-month-day | -s -] [-bBgGhn]' + opts = '[-d delev]* [-D delev]* [-e elev]* [-m elev]* [-h [-L] | -u | -L]' + opts += ' [-l lat:lon | -l loc] [-s year-month-day | -s -] [-r num[h|m|s]]' + opts += ' [-bBgGnN]' print('Usage: %s %s' % (argv0, opts), file = sys.stderr) sys.exit(1) i, n = 1, len(sys.argv) def getarg(): global i, j, n, m if j < m: - rc = arg[j] + rc = arg[j:] j = m return rc else: @@ -42,13 +49,15 @@ while i < n: if arg == '--': i += 1 break - elif arg.startwith('-'): + elif arg.startswith('-'): j, m = 1, len(arg) while j < m: c = arg[j] j += 1 if c == 'd': - deriv.append(getarg()) + dderiv.append(getarg()) + elif c == 'D': + nderiv.append(getarg()) elif c == 'e': evening.append(getarg()) elif c == 'm': @@ -57,6 +66,8 @@ while i < n: loc = getarg() elif c == 's': stop_date = getarg() + elif c == 'r': + res = getarg() elif c == 'b': blue = True elif c == 'B': @@ -67,15 +78,34 @@ while i < n: ungold = True elif c == 'h': human = True + elif c == 'u': + unix = True + elif c == 'L': + local = True elif c == 'n': noon = True + elif c == 'N': + night = True else: usage() - j += 1 i += 1 else: break -if i != n: +if i != n or (human and unix): + usage() + + +## Parse resolution +if len(res) < 2: + usage() +mul = {'s' : 1.0, 'm' : 60.0, 'h' : 60 * 60.0} +suffix = res[-1] +value = res[:-1] +if '.' in value: + usage() +try: + res = int(value) * mul[suffix] +except: usage() @@ -83,7 +113,8 @@ if i != n: try: evening = [float(e) for e in evening] morning = [float(e) for e in morning] - deriv = [float(e) for e in deriv] + dderiv = [float(e) for e in dderiv] + nderiv = [float(e) for e in nderiv] for e in evening + morning: if abs(e) > 90: usage() @@ -91,7 +122,7 @@ except: usage() -## Parse -bBgGn +## Parse -bBgGnN if blue: morning.append(sol.SOLAR_ELEVATION_RANGE_BLUE_HOUR[0]) evening.append(sol.SOLAR_ELEVATION_RANGE_BLUE_HOUR[1]) @@ -105,11 +136,13 @@ if ungold: morning.append(sol.SOLAR_ELEVATION_RANGE_GOLDEN_HOUR[1]) evening.append(sol.SOLAR_ELEVATION_RANGE_GOLDEN_HOUR[0]) if noon: - deriv.append(0.0) + dderiv.append(0.0) +if night: + nderiv.append(0.0) ## Fallback options -if len(morning) == 0 and len(evening) == 0 and len(deriv) == 0: +if len(morning) == 0 and len(evening) == 0 and len(dderiv) == 0 and len(nderiv) == 0: morning.append(sol.SOLAR_ELEVATION_RANGE_BLUE_HOUR[0]) evening.append(sol.SOLAR_ELEVATION_RANGE_BLUE_HOUR[1]) @@ -204,3 +237,107 @@ else: stop_time += 24 * 60 * 60 stop_time -= (time.altzone if is_summer else time.timezone) + +def get_elev(elev, start, morning): + end = start + 0.0099 + while start < end: + rc = sol.future_elevation(lat, lon, elev, start) + if rc is None: + return (None, end) + else: + start = rc + 1e-06 + d = sol.solar_elevation(lat, lon, rc + 3e-09) + d -= sol.solar_elevation(lat, lon, rc) + if d >= 0 if morning else d <= 0: + return (sol.julian_centuries_to_epoch(rc), start) + return (None, end) + +def get_deriv(delev, start, daytime): + end = start + 0.0099 + while start < end: + rc = sol.future_elevation_derivative(lat, lon, delev, start) + if rc is None: + return (None, end) + else: + start = rc + 1e-06 + elev = sol.solar_elevation(lat, lon, rc) + if elev >= 0 if daytime else elev <= 0: + return (sol.julian_centuries_to_epoch(rc), start) + return (None, end) + +def get_morning(elev, start): + return get_elev(elev, start, True) + +def get_evening(elev, start): + return get_elev(elev, start, False) + +def get_day(delev, start): + return get_deriv(delev, start, True) + +def get_night(delev, start): + return get_deriv(delev, start, False) + +now = sol.epoch_to_julian_centuries(time.time()) +class State: + def __init__(self, val, fun): + self.start = now + self.val = val + self.fun = fun + def next(self): + (rc, self.start) = self.fun(self.val, self.start) + return (rc, self.start) + +morning = [State(v, get_morning) for v in morning] +evening = [State(v, get_evening) for v in evening] +dderiv = [State(v, get_day) for v in dderiv] +nderiv = [State(v, get_night) for v in nderiv] +states = morning + evening + dderiv + nderiv + + +# So we can stop of the pipe breaks (useful with -s -) +def print(msg): + msg = (str(msg) + '\n').encode('utf-8') + ptr, n = 0, len(msg) + while ptr < n: + ptr += os.write(1, msg[ptr:]) + +def parse_time(t, localtime, tzname): + tm = time.localtime(t) if localtime else time.gmtime(t) + if localtime and tm.tm_isdst < 0: + tm = time.gmtime(t) + localtime = False + if not localtime: + tz = 'UTC' if tzname else 'Z' + else: + tz = time.strftime('%Z' if tzname else '%z', tm) + return (tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tz) + +jc_stop_time = sol.epoch_to_julian_centuries(stop_time) if stop_time is not None else None +months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') +try: + while len(states) > 0: + n = len(states) + i = 0 + while i < n: + (t, s) = states[i].next() + if t is not None and (stop_time is None or t < stop_time): + t = int(t / res + 0.5) * res + if unix: + print(int(t)) + else: + t = parse_time(t, local, human) + if human: + (y, m, d, H, M, S, z) = t + t = (y, m, months[m - 1], d, H, M, S, z) + print('%i-(%02i)%s-%02i %02i:%02i:%02i %s' % t) + else: + print('%i-%02i-%02iT%02i:%02i:%02i%s' % t) + if jc_stop_time is not None and s >= jc_stop_time: + del states[i] + n -= 1 + else: + i += 1 +except KeyboardInterrupt as e: + sys.exit(0) +except BrokenPipeError as e: + sys.exit(0) |