class Object

Public Instance Methods

apod() click to toggle source
# File bin/astropanel, line 987
def apod # GET ASTRONOMY PICTRUE OF THE DAY
  apod = Net::HTTP.get(URI("https://apod.nasa.gov/apod/astropix.html"))
  apod.sub!(/^.*IMG SRC=./m, "")
  apod.sub!(/\".*/m, "")
  apod = "https://apod.nasa.gov/apod/" + apod
  `curl -s "#{apod}" > /tmp/apod.jpg`
end
cmd?(command) click to toggle source
# File bin/astropanel, line 46
def cmd?(command)
  system("which #{command} > /dev/null 2>&1")
end
conf_write() click to toggle source
# File bin/astropanel, line 796
def conf_write # WRITE TO .AP.CONF
  if File.exist?(Dir.home+'/.ap.conf')
    conf = File.read(Dir.home+'/.ap.conf')
  else
    conf = ""
  end
  if @write_conf_all
    conf.sub!(/^@loc.*/, "@loc = \"#{@loc}\"")
    conf.sub!(/^@lat.*/, "@lat = #{@lat}")
    conf.sub!(/^@lon.*/, "@lon = #{@lon}")
    conf.sub!(/^@cloudlimit.*/, "@cloudlimit = #{@cloudlimit}")
    conf.sub!(/^@humiditylimit.*/, "@humiditylimit = #{@humiditylimit}")
    conf.sub!(/^@templimit.*/, "@templimit = #{@templimit}")
    conf.sub!(/^@windlimit.*/, "@windlimit = #{@windlimit}")
    w_u_msg("Press W again to write this to .ap.conf:\n\n" + conf)
    if getchr == 'W'
      w_b_info(" Parameters written to .ap.conf")
      @w_b.update = false
    else
      w_b_info(" Config NOT updated")
      @w_b.update = false
      return
    end
  end
  File.write(Dir.home+'/.ap.conf', conf)
end
get_cond(t) click to toggle source
# File bin/astropanel, line 776
def get_cond(t) # GREEN/YELLOW/RED FROM CONDITIONS
  details = @weather_point[t]["data"]["instant"]["details"]
  cond = 0
  cond += 1 if details["cloud_area_fraction"].to_i > @cloudlimit
  cond += 1 if details["cloud_area_fraction"].to_i > @cloudlimit + (100 - @cloudlimit)/2 
  cond += 2 if details["cloud_area_fraction"].to_i > 90
  cond += 1 if details["relative_humidity"].to_i > @humiditylimit
  cond += 1 if details["air_temperature"].to_i < @templimit
  cond += 1 if details["air_temperature"].to_i + 7 < @templimit
  cond += 1 if details["wind_speed"].to_i > @windlimit
  cond += 1 if details["wind_speed"].to_i > @windlimit * 2
  case cond
  when 0..1
    return 1
  when 2..3
    return 2
  else
    return 3
  end
end
get_events() click to toggle source
# File bin/astropanel, line 760
def get_events # ASTRONOMICAL EVENTS
  events = {}
  eventsURI   = "https://in-the-sky.org//rss.php?feed=dfan&latitude=#{@lat}&longitude=#{@lon}&timezone=#{@loc}"
  events_rss  = Net::HTTP.get(URI(eventsURI))
  events_data = events_rss.scan(/<item>.*?<\/item>/m)
  events_data.each do |e|
    date  = Time.parse(e[/<title>(.{11})/,1]).strftime("%F")
    time  = e[/\d\d:\d\d:\d\d/]
    event = e[/<description>&lt;p&gt;(.*?).&lt;\/p&gt;<\/description>/,1].decoder
    event.gsub!(/&amp;deg;/, "°")
    event.gsub!(/&amp;#39;/, "'")
    link  = e[/<link>(.*?)<\/link>/,1]
    events[date] = {"time" => time, "event" => event, "link" => link} if date >= @today
  end
  return events
end
get_planets() click to toggle source
# File bin/astropanel, line 741
def get_planets # PLANET EPHEMERIS DATA
  planets = {}
  12.times do |x|
    date          = (Time.now + 86400 * (x - 1)).strftime("%F")
    p             = Ephemeris.new(date, @lat, @lon, @tz.to_i)
    planets[date] = {"table" => p.print, 
                     "srise" => p.sun[5],     "sset" => p.sun[7],
                     "mrise" => p.moon[5],    "mset" => p.moon[7],
                     "phase" => p.mphase,     "ph_s" => p.mph_s,
                     "Mrise" => p.mercury[5], "Mset" => p.mercury[7],
                     "Vrise" => p.venus[5],   "Vset" => p.venus[7],
                     "Arise" => p.mars[5],    "Aset" => p.mars[7],
                     "Jrise" => p.jupiter[5], "Jset" => p.jupiter[7],
                     "Srise" => p.saturn[5],  "Sset" => p.saturn[7],
                     "Urise" => p.uranus[5],  "Uset" => p.uranus[7],
                     "Nrise" => p.neptune[5], "Nset" => p.neptune[7]}
  end
  return planets
end
get_weather() click to toggle source
# File bin/astropanel, line 677
def get_weather # WEATHER FORECAST FROM MET.NO
  begin
    uri  = URI.parse("https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=#{@lat}&lon=#{@lon}")
    req  = Net::HTTP::Get.new(uri)
    req["User-Agent"] = "astropanel/1.0 g@isene.com"
    json = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => true) do |http|
      http.request(req)
    end
    weather_data   = JSON.parse(json.body)
    @weather_point = weather_data["properties"]["timeseries"]
    weather_size   = @weather_point.size
    @weather       = []
    weather_size.times do |t|
      details = @weather_point[t]["data"]["instant"]["details"]
      time    = @weather_point[t]["time"]
      date    = time[0..9]
      hour    = time[11..12]
      wthr    = details["cloud_area_fraction"].to_i.to_s.rjust(5) + "%"
      wthr   += details["relative_humidity"].to_s.rjust(7)
      wthr   += details["air_temperature"].to_s.rjust(6)
      wind    = details["wind_speed"].to_s + " ("
      case details["wind_from_direction"].to_i
      when 0..22
        wdir = "N"
      when 23..67
        wdir = "NE"
      when 68..112
        wdir = "E"
      when 113..158
        wdir = "SE"
      when 159..203
        wdir = "S"
      when 204..249
        wdir = "SW"
      when 250..294
        wdir = "W"
      when 295..340
        wdir = "NW"
      else
        wdir = "N"
      end
      wind += wdir.rjust(2)
      wthr += wind.rjust(10) + ")"
      info  = date + " (" + Date.parse(date).strftime("%A") + ") #{hour}:00\n\n" 
      cld   = "Clouds (-/+)  " + details["cloud_area_fraction"].to_i.to_s + "% (" 
      cld  += details["cloud_area_fraction_low"].to_i.to_s + "% " + details["cloud_area_fraction_high"].to_i.to_s + "%)"
      info += cld.ljust(34)
      details["fog_area_fraction"] == 0 ? fog = "-" : fog = (details["fog_area_fraction"].to_f.round(1)).to_s + "%" 
      info += "Humidity (fog)  " + details["relative_humidity"].to_s + "% (" + fog + ")\n"
      wnd   = "Wind [gusts]  " + details["wind_speed"].to_s + " m/s (" + wdir + ") [" + details["wind_speed_of_gust"].to_s + "]"
      info += wnd.ljust(34)
      info += "Temp (dew)      " + details["air_temperature"].to_s + "°C ("
      info += details["dew_point_temperature"].to_s + "°C)\n"
      air   = "Air pressure  " + details["air_pressure_at_sea_level"].to_i.to_s + " hPa   "
      info += air.ljust(34)
      uv    = details["ultraviolet_index_clear_sky"].to_s
      uv    = "-" if uv == ""
      info += "UV index        " + uv + "\n"
      @weather.push([date, hour, wthr, info])
    rescue
      w_b_info("Not able to retrieve weather data from met.no")
    end
  end
end
getchr() click to toggle source

GENERIC FUNCTIONS

# File bin/astropanel, line 541
def getchr # PROCESS KEY PRESSES
  # Note: Curses.getch blanks out @w_t
  # @w_l.getch makes Curses::KEY_DOWN etc not work
  # Therefore resorting to the generic method
  c = STDIN.getch(min: 0, time: 1) 
  case c
  when "\e"    # ANSI escape sequences
    case $stdin.getc
    when '['   # CSI
      case $stdin.getc
      when 'A' then chr = "UP"
      when 'B' then chr = "DOWN"
      when 'C' then chr = "RIGHT"
      when 'D' then chr = "LEFT"
      when 'Z' then chr = "S-TAB"
      when '2' then chr = "INS"    ; STDIN.getc
      when '3' then chr = "DEL"    ; STDIN.getc
      when '5' then chr = "PgUP"   ; STDIN.getc
      when '6' then chr = "PgDOWN" ; STDIN.getc
      when '7' then chr = "HOME"   ; STDIN.getc
      when '8' then chr = "END"    ; STDIN.getc
      end
    end
  when "", "" then chr = "BACK"
  when "" then chr = "WBACK"
  when "" then chr = "LDEL"
  when "" then chr = "C-T"
  when "\r" then chr = "ENTER"
  when "\t" then chr = "TAB"
  when /./  then chr = c
  end
  return chr
end
image_show(image) click to toggle source

RIGHT LOWER WINDOW FUNCTIONS

# File bin/astropanel, line 943
def image_show(image)# SHOW THE SELECTED IMAGE IN TOP RIGHT WINDOW
  return unless @showimage
  return if @noimage
  # Pass "clear" to clear the window for previous image
  begin
    terminfo    = `xwininfo -id $(xdotool getactivewindow)`
    term_w      = terminfo.match(/Width: (\d+)/)[1].to_i
    term_h      = terminfo.match(/Height: (\d+)/)[1].to_i
    char_w      = term_w / Curses.cols
    char_h      = term_h / Curses.lines
    img_x       = char_w * (@w_l_width + 1)
    img_y       = char_h * 23
    img_max_w   = char_w * (Curses.cols - @w_l_width - 2)
    img_max_h   = char_h * (@w_d.maxy - 2)
    if image == "clear"
      img_max_w += 2
      img_max_h += 2
      `echo "6;#{img_x};#{img_y};#{img_max_w};#{img_max_h};\n4;\n3;" | #{@w3mimgdisplay} 2>/dev/null`
    else
      img_w,img_h = `identify -format "%[fx:w]x%[fx:h]" #{image} 2>/dev/null`.split('x')
      img_w       = img_w.to_i
      img_h       = img_h.to_i
      if img_w > img_max_w
        img_h = img_h * img_max_w / img_w 
        img_w = img_max_w
      end
      if img_h > img_max_h
        img_w = img_w * img_max_h / img_h
        img_h = img_max_h
      end
      `echo "0;1;#{img_x};#{img_y};#{img_w};#{img_h};;;;;\"#{image}\"\n4;\n3;" | #{@w3mimgdisplay} 2>/dev/null`
    end
  rescue
    w_b_info("Error showing image")
  end
end
main_getkey() click to toggle source
# File bin/astropanel, line 574
def main_getkey # GET KEY FROM USER
  chr = getchr
  case chr
  when '?' # Show helptext in right window
    w_u_msg(@help)
  when 'UP'
    @index = @index <= @min_index ? @max_index : @index - 1
    @w_u.update = true
  when 'DOWN'
    @index = @index >= @max_index ? @min_index : @index + 1
    @w_u.update = true
  when 'PgUP'
    @index -= @w_l.maxy - 2
    @index = @min_index if @index < @min_index
    @w_u.update = true
  when 'PgDOWN'
    @index += @w_l.maxy - 2
    @index = @max_index if @index > @max_index
    @w_u.update = true
  when 'HOME'
    @index = @min_index
    @w_u.update = true
  when 'END'
    @index = @max_index
    @w_u.update = true
  when 'l'
    @loc = w_b_getstr("Loc: ", @loc)
    @w_u.update = true
  when 'a'
    @lat = w_b_getstr("Lat: ", @lat.to_s).to_f
    @w_u.update = true
  when 'o'
    @lon = w_b_getstr("Lon: ", @lon.to_s).to_f
    @w_u.update = true
  when 'c'
    @cloudlimit = w_b_getstr("Cloudlimit: ", @cloudlimit.to_s).to_i
    @w_u.update = true
  when 'h'
    @humiditylimit = w_b_getstr("Humiditylimit: ", @humiditylimit.to_s).to_i
    @w_u.update = true
  when 't'
    @templimit = w_b_getstr("Templimit: ", @templimit.to_s).to_i
    @w_u.update = true
  when 'w'
    @windlimit = w_b_getstr("Windlimit: ", @windlimit.to_s).to_i
    @w_u.update = true
  when 'b'
    @bortle = w_b_getstr("Bortle: ", @bortle.to_s).to_f.round(1)
    @w_u.update = true
  when 'e'
    ev = "\nUPCOMING EVENTS:\n\n"
    @events.each do |key, val|  
      ev += key + " " + val["time"] + " " + val["event"] + "\n"
    end
    w_u_msg(ev)
  when 's'
    starchart
    @image = "/tmp/starchart.jpg"
    image_show("clear")
    image_show(@image)
  when 'S'
    begin
      Thread.new { system("xdg-open '/tmp/starchart.jpg'") }
    rescue
    end
    @break = true
  when 'A'
    image_show("clear")
    @image = "/tmp/apod.jpg"
    image_show(@image)
  when 'ENTER' # Refresh image
    image_show(@image)
    @w_u.update = true
  when 'r' # Refresh all windows
    @break = true
  when '@' # Enter "Ruby debug"
    @w_b.nohistory = false
    cmd = w_b_getstr("◆ ", "")
    begin
      @w_b.text = eval(cmd)
      @w_b.fill
      @w_b.write
    rescue StandardError => e
      w_b_info("Error: #{e.inspect}")
    end
    @w_b.update = false
  when 'R' # Reload .ap.conf
    if File.exist?(Dir.home+'/.ap.conf')
      load(Dir.home+'/.ap.conf')
    end
    w_b_info(" Config reloaded")
    @w_b.update = false
  when 'W' # Write all parameters to .ap.conf
    @write_conf_all = true
    conf_write
  when 'q' # Exit
    @write_conf = true
    exit 0
  when 'Q' # Exit without writing to .ap.conf
    @write_conf = false
    exit 0
  end
end
print_p(ix, date, rise, set, c) click to toggle source

LEFT WINDOW FUNCTIONS

starchart() click to toggle source
# File bin/astropanel, line 979
def starchart # GET AND SHOW STARCHART FOR SELECTED TIME
  d = Time.parse(@weather[@index][0]).strftime("%d").to_i
  m = Time.parse(@weather[@index][0]).strftime("%m").to_i
  y = Time.parse(@weather[@index][0]).strftime("%Y").to_i
  starchartURI = "https://www.stelvision.com/carte-ciel/visu_carte.php?stelmarq=C&mode_affichage=normal&req=stel&date_j_carte=#{d}&date_m_carte=#{m}&date_a_carte=#{y}&heure_h=#{@weather[@index][1].to_i}&heure_m=00&longi=#{@lon}&lat=#{@lat}&tzone=#{@tz.to_i}.0&dst_offset=1&taille_carte=1200&fond_r=255&fond_v=255&fond_b=255&lang=en"
  `curl -s "#{starchartURI}" > /tmp/stars.png`
  `convert /tmp/stars.png /tmp/starchart.jpg`
end
w_b_getstr(pretext, text) click to toggle source
# File bin/astropanel, line 1004
def w_b_getstr(pretext, text) # A SIMPLE READLINE-LIKE ROUTINE
  Curses.curs_set(1)
  Curses.echo
  stk = 0
  @history.insert(stk, text)
  pos = @history[stk].length
  chr = ""
  while chr != "ENTER"
    @w_b.setpos(0,0)
    @w_b.text = pretext + @history[stk]
    @w_b.text += " " * (@w_b.maxx - text.length) if text.length < @w_b.maxx
    @w_b.write
    @w_b.setpos(0,pretext.length + pos)
    @w_b.refresh
    chr = getchr
    case chr
    when 'UP'
      unless @w_b.nohistory
        unless stk == @history.length - 1
          stk += 1 
          pos = @history[stk].length
        end
      end
    when 'DOWN'
      unless @w_b.nohistory
        unless stk == 0
          stk -= 1 
          pos = @history[stk].length
        end
      end
    when 'RIGHT'
      pos += 1 unless pos > @history[stk].length
    when 'LEFT'
      pos -= 1 unless pos == 0
    when 'HOME'
      pos = 0
    when 'END'
      pos = @history[stk].length
    when 'DEL'
      @history[stk][pos] = ""
    when 'BACK'
      unless pos == 0
        pos -= 1
        @history[stk][pos] = ""
      end
    when 'WBACK'
      unless pos == 0
        until @history[stk][pos - 1] == " " or pos == 0
          pos -= 1
          @history[stk][pos] = ""
        end
        if @history[stk][pos - 1] == " "
          pos -= 1
          @history[stk][pos] = ""
        end
      end
    when 'LDEL'
      @history[stk] = ""
      pos = 0
    when /^.$/
      @history[stk].insert(pos,chr)
      pos += 1
    end
  end
  curstr = @history[stk]
  @history.shift if @w_b.nohistory
  unless @w_b.nohistory
    @history.uniq!
    @history.compact!
    @history.delete("")
  end
  Curses.curs_set(0)
  Curses.noecho
  return curstr
end
w_b_info(info) click to toggle source

BOTTOM WINDOW FUNCTIONS

# File bin/astropanel, line 995
def w_b_info(info) # SHOW INFO IN @W_B
  @w_b.clr
  info      = "?=Show Help | Edit: l=Loc a=Lat o=Lon | s=Starchart for selected time | ENTER=Refresh r=Redraw q=Quit Q=Quit (no config save)" if info == nil
  info      = info[1..(@w_b.maxx - 3)] + "…" if info.length + 3 > @w_b.maxx 
  info     += " " * (@w_b.maxx - info.length) if info.length < @w_b.maxx
  @w_b.text = info
  @w_b.write
  @w_b.update = false
end
w_l_info() click to toggle source
# File bin/astropanel, line 849
def w_l_info # SHOW WEATHER CONDITION AND RISE/SET IN @w_l
  @w_l.clr
  @w_l.p(254, 238, 0, "YYYY-MM-DD  HH  Cld%   Hum%    °C   Wind m/s  * ● ○ m V M J S U N\n")
  ix = 0; t = 1; prev_date = ""
  ix = @index - @w_l.maxy/2 if @index > @w_l.maxy/2 and @weather.size > @w_l.maxy
  while ix < @weather.size and t < @w_l.maxy do
    marker = 0
    color  = color_pair(get_cond(ix))
    date = @weather[ix][0]
    date == prev_date ? line = "            " : line = date + "  "
    @w_l.attron(color) { @w_l << line } 
    marker = Curses::A_UNDERLINE if ix == @index
    line   = @weather[ix][1] + @weather[ix][2]
    @w_l.attron(color | marker) { @w_l << line }
    if @events.has_key?(date)
      @events[date]["time"][0..1] == @weather[ix][1] ? line = "  !" : line = "   "
    else
      line = "   "
    end
    @w_l.attron(color) { @w_l << line }
    begin
      print_p(ix, date, "srise", "sset", 226)
      c0 = ((50 - (@planets[date]["phase"] - 50).abs)/2.7 + 237).to_i
      print_p(ix, date, "mrise", "mset", c0)
      print_p(ix, date, "Mrise", "Mset", 130)
      print_p(ix, date, "Vrise", "Vset", 153)
      print_p(ix, date, "Arise", "Aset", 124)
      print_p(ix, date, "Jrise", "Jset", 108)
      print_p(ix, date, "Srise", "Sset", 142)
      print_p(ix, date, "Urise", "Uset", 24)
      print_p(ix, date, "Nrise", "Nset", 27)
    rescue
    end
    clrtoeol
    @w_l << "\n"
    prev_date = date unless date == prev_date
    ix += 1
    t  += 1
  end
  @w_l.refresh
end
w_t_info() click to toggle source

TOP WINDOW FUNCTIONS

# File bin/astropanel, line 823
def w_t_info # SHOW INFO IN @w_t
  @w_t.clr
  text  = " #{@loc} (tz=#{'%02d' % @tz}) Lat: #{@lat}, Lon: #{@lon} " 
  text += "(Bortle #{@bortle})  "
  text += "Updated: #{@time} (JD: 24#{DateTime.now.amjd().to_f.round(4) + 0.5})"
  text += " " * (@w_t.maxx - text.length) if text.length < @w_t.maxx
  @w_t.text = text
  @w_t.write
end
w_u_info() click to toggle source
# File bin/astropanel, line 897
def w_u_info # ASTRO INFO IN @w_u
  @w_u.clr
  color  = color_pair(get_cond(@index)) 
  info   = @weather[@index][3].split("\n")
  # Moon phase
  mp     = 29.530588861
  nm     = 2459198.177777778
  fm     = nm + mp/2
  y      = @weather[@index][0][0..3].to_i
  m      = @weather[@index][0][5..6].to_i
  d      = @weather[@index][0][8..9].to_i
  h      = @weather[@index][1].to_i
  jd     = DateTime.new(y, m, d, h, 0, 0, @tz).ajd.to_f
  mp_n   = (100*((jd - nm) % mp) / mp).round(1)
  ph_a   = ((jd - fm) % mp) / mp * 360
  mp_ip  = ((1 + Math.cos(ph_a.deg))*50).to_i
  mp_s   = @planets[@weather[@index][0]]["ph_s"]
  title  = info[0] + " (Moon: #{mp_n}/#{mp_ip}% #{mp_s})"
  @w_u.attron(color) { @w_u << title }
  @w_u.write
  info.shift
  @w_u.maxx < Curses.cols ? maxx = @w_u.maxx : maxx = Curses.cols
  info.each_with_index do |line, index| 
    line += " "*(maxx - line.length - 1)
    info[index] = line
  end
  @w_u.text  = info.join("\n")
  @w_u.text += "\n\n"
  @w_u.text += @planets[@weather[@index][0]]["table"]
  @w_u.write
  date = @weather[@index][0]

  @w_u << "\n"
  if @events.has_key?(date)
    text  = "@ " + @events[date]["time"] + ": "
    text += @events[date]["event"] + "\n"
    text += @events[date]["link"] + "\n"
    if @events[date]["time"][0..1] == @weather[@index][1]
      @w_u.p(111,0,Curses::A_BOLD,text)
    else
      @w_u.text = text
      @w_u.write
    end
  end
end
w_u_msg(msg) click to toggle source

RIGHT UPPER WINDOW FUNCTIONS

# File bin/astropanel, line 891
def w_u_msg(msg) # MESSAGES IN @w_u
  @w_u.clr
  @w_u.text = msg
  @w_u.write
  @w_u.update = false
end