astropanel 2.3 → 2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/astropanel +103 -68
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 939fa439565527c2c8b9f0ce4e1e13ab008bd3c23f153efd9e2e01d65a50fe45
|
4
|
+
data.tar.gz: 368bbb21a445bfff885cbf6a9b1f526fe11531cdb9be1ad0ad02760ca5818416
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f393f7af8500905358502ef1a78b1e9c3808e883f8febc21bec01f84221b101fd00a305a5e7c6d522baf1fcf1343e9f9c42765fc542e2b673d925739880fa272
|
7
|
+
data.tar.gz: dd1447a1e2c3cc56f4e4d30e5284d0ceef71bc45e2dae203017b054789e4c3bbcb6ef826a682751bb39198a543c26203b03088571765ede52211e1fc1b5c5148
|
data/bin/astropanel
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
# for any damages resulting from its use. Further, I am under no
|
15
15
|
# obligation to maintain or extend this software. It is provided
|
16
16
|
# on an 'as is' basis without any expressed or implied warranty.
|
17
|
-
# Version: 2.
|
17
|
+
# Version: 2.6: Bug fix
|
18
18
|
|
19
19
|
# LOAD MODULES {{{1
|
20
20
|
require 'io/console'
|
@@ -31,9 +31,6 @@ include Rcurses::Input
|
|
31
31
|
include Rcurses::Cursor
|
32
32
|
|
33
33
|
# BASIC SETUP {{{1
|
34
|
-
$stdin.raw!
|
35
|
-
$stdin.echo = false
|
36
|
-
|
37
34
|
CONFIG_FILE = File.join(Dir.home, '.ap.conf')
|
38
35
|
|
39
36
|
# CLASS EXTENSIONS {{{1
|
@@ -56,13 +53,6 @@ class String # {{{2
|
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
59
|
-
# AT_EXIT {{{1
|
60
|
-
at_exit do
|
61
|
-
$stdin.cooked!
|
62
|
-
$stdin.echo = true
|
63
|
-
Rcurses.clear_screen
|
64
|
-
Cursor.show
|
65
|
-
end
|
66
56
|
|
67
57
|
# EPHEMERIS CORE {{{1
|
68
58
|
class Ephemeris
|
@@ -728,27 +718,40 @@ class AstroPanelApp
|
|
728
718
|
@header.say(txt.ljust(cols))
|
729
719
|
end
|
730
720
|
|
731
|
-
|
721
|
+
# Update the top‐bar title line, safely handling missing planet data
|
722
|
+
def update_titles
|
732
723
|
_, cols = IO.console.winsize
|
733
724
|
|
734
|
-
|
735
|
-
|
725
|
+
# Base limits display
|
726
|
+
title = " …#{@cloudlimit}% …#{@humiditylimit}% " \
|
727
|
+
"#{@templimit}°C… …#{@windlimit}m/s".fg(244)
|
736
728
|
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
729
|
+
# Current date/hour
|
730
|
+
if @weather[@index]
|
731
|
+
date = @weather[@index][:date]
|
732
|
+
hr = @weather[@index][:hour]
|
733
|
+
col = cond_color(@index)
|
734
|
+
else
|
735
|
+
date = nil
|
736
|
+
hr = nil
|
737
|
+
col = 244
|
738
|
+
end
|
743
739
|
|
744
740
|
title << ' ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ '.fg(244)
|
745
|
-
title << "#{date} (#{Date.parse(date).strftime("%A")}) #{hr}:00".b.fg(col)
|
746
|
-
|
741
|
+
title << "#{date}#{ date ? " (#{Date.parse(date).strftime("%A")}) #{hr}:00" : ""}".b.fg(col)
|
742
|
+
|
743
|
+
# Safely fetch moon‐phase info (mphase/mph_s) if it exists
|
744
|
+
if date && (pd = @planets[date])
|
745
|
+
mp, mp_name = pd.values_at(:mphase, :mph_s)
|
746
|
+
title << " Moon: #{mp_name} (#{mp}%)".fg(244)
|
747
|
+
else
|
748
|
+
title << " Moon: unavailable".fg(244)
|
749
|
+
end
|
747
750
|
|
751
|
+
@titles.clear
|
748
752
|
@titles.say(title.ljust(cols))
|
749
753
|
end
|
750
754
|
|
751
|
-
|
752
755
|
def update_footer # {{{2
|
753
756
|
_, cols = IO.console.winsize
|
754
757
|
cmds = "?=Help l=Loc a=Lat o=Lon c=Cloud h=Hum t=Temp w=Wind b=Bortle " \
|
@@ -758,70 +761,81 @@ class AstroPanelApp
|
|
758
761
|
end
|
759
762
|
|
760
763
|
def update_left # {{{2
|
761
|
-
|
762
|
-
date_n =
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
#
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
764
|
+
date_o = ''
|
765
|
+
date_n = ''
|
766
|
+
|
767
|
+
all_lines = @weather.each_with_index.map do |w, i|
|
768
|
+
col = cond_color(i)
|
769
|
+
|
770
|
+
# Safely fetch planet data for this date (may be nil)
|
771
|
+
pd = @planets[w[:date]] || {}
|
772
|
+
mp = pd[:mphase]
|
773
|
+
|
774
|
+
# Prepare date display, only show the date when it changes
|
775
|
+
date_o = date_n
|
776
|
+
date_n = w[:date]
|
777
|
+
date_s = (date_n == date_o ? ' '.ljust(10) : date_n)
|
778
|
+
|
779
|
+
# Fixed‐width weather columns
|
780
|
+
hour_s = w[:hour]
|
772
781
|
cloud_s = "#{w[:cloud]}%".rjust(4)
|
773
782
|
hum_s = "#{w[:humidity]}%".rjust(5)
|
774
783
|
tmp_s = "#{w[:temp]}°C".rjust(6)
|
775
784
|
wnd_s = "#{w[:wind]}(#{w[:wdir]})".rjust(8)
|
776
785
|
|
777
|
-
#
|
786
|
+
# Build the left‐pane row
|
778
787
|
row = "#{date_s} ".fg(col)
|
779
788
|
ul = "#{hour_s} #{cloud_s} #{hum_s} #{tmp_s} #{wnd_s}".fg(col)
|
780
789
|
ul = ul.u if i == @index
|
781
790
|
row += ul
|
782
791
|
|
783
|
-
#
|
792
|
+
# Event marker
|
784
793
|
if ev = @events[w[:date]] and ev[:time][0..1] == w[:hour]
|
785
794
|
row += " !".fg(col)
|
786
795
|
else
|
787
796
|
row += " "
|
788
797
|
end
|
789
798
|
|
790
|
-
#
|
791
|
-
BODIES.each_with_index do |b,
|
792
|
-
rise
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
799
|
+
# Visibility blocks for Sun, Moon & planets
|
800
|
+
BODIES.each_with_index do |b, j|
|
801
|
+
# Extract just the hour component from rise/set, convert to Integer
|
802
|
+
rise_h = pd[:"#{b}_rise"] ? pd[:"#{b}_rise"][0..1].to_i : nil
|
803
|
+
set_h = pd[:"#{b}_set"] ? pd[:"#{b}_set"][0..1].to_i : nil
|
804
|
+
hr = w[:hour].to_i
|
805
|
+
|
806
|
+
above = if rise_h.nil? || set_h.nil?
|
807
|
+
false
|
808
|
+
elsif rise_h > set_h
|
809
|
+
(hr >= rise_h) || (hr <= set_h)
|
810
|
+
else
|
811
|
+
(hr >= rise_h) && (hr <= set_h)
|
812
|
+
end
|
813
|
+
|
814
|
+
# Choose block character and color
|
815
|
+
block_char = (0..1) === j ? '█' : '┃'
|
816
|
+
if above
|
817
|
+
color = (b == 'moon' ? moon_phase_color(mp) : BODY_COLORS[b])
|
818
|
+
block = block_char.fg(color)
|
800
819
|
else
|
801
|
-
|
820
|
+
block = ' '
|
802
821
|
end
|
803
|
-
|
822
|
+
|
804
823
|
row << " #{block}"
|
805
824
|
end
|
806
825
|
|
807
826
|
row
|
808
827
|
end
|
809
828
|
|
810
|
-
#
|
829
|
+
# Write into the pane buffer and center the selection
|
811
830
|
@left.text = all_lines.join("\n")
|
831
|
+
height = @left.h
|
812
832
|
|
813
|
-
# figure out how many rows we can show
|
814
|
-
height = @left.h
|
815
|
-
|
816
|
-
# center the selection (3-row “scroll‐off”)…
|
817
833
|
top = @index - (height / 2)
|
818
834
|
top = 0 if top < 0
|
819
835
|
max_top = all_lines.size - height
|
820
836
|
top = max_top if top > max_top
|
821
837
|
|
822
838
|
@left.ix = top
|
823
|
-
|
824
|
-
# redraw just the left pane
|
825
839
|
@left.refresh
|
826
840
|
end
|
827
841
|
|
@@ -914,11 +928,23 @@ class AstroPanelApp
|
|
914
928
|
end
|
915
929
|
|
916
930
|
def get_weather # {{{2
|
931
|
+
# Fetch weather from met.no, but never let network errors crash the app
|
917
932
|
uri = URI("https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=#{@lat}&lon=#{@lon}")
|
918
933
|
req = Net::HTTP::Get.new(uri)
|
919
934
|
req['User-Agent'] = 'astropanel/1.0 g@isene.com'
|
920
|
-
|
921
|
-
|
935
|
+
|
936
|
+
begin
|
937
|
+
res = Net::HTTP.start(uri.hostname, uri.port,
|
938
|
+
use_ssl: true,
|
939
|
+
read_timeout: 10) do |http|
|
940
|
+
http.request(req)
|
941
|
+
end
|
942
|
+
rescue SocketError, Socket::ResolutionError, Timeout::Error, Net::OpenTimeout => e
|
943
|
+
@footer.say("⚠️ Weather fetch failed: #{e.class}: #{e.message}")
|
944
|
+
@weather = []
|
945
|
+
return
|
946
|
+
end
|
947
|
+
|
922
948
|
if res.is_a?(Net::HTTPSuccess)
|
923
949
|
series = JSON.parse(res.body)
|
924
950
|
.dig('properties','timeseries') || []
|
@@ -939,7 +965,7 @@ class AstroPanelApp
|
|
939
965
|
}
|
940
966
|
end
|
941
967
|
else
|
942
|
-
@footer.say("Weather API error: #{res.code} #{res.message}")
|
968
|
+
@footer.say("⚠️ Weather API error: #{res.code} #{res.message}")
|
943
969
|
@weather = []
|
944
970
|
end
|
945
971
|
end
|
@@ -985,25 +1011,34 @@ class AstroPanelApp
|
|
985
1011
|
end
|
986
1012
|
|
987
1013
|
def get_planets # {{{2
|
1014
|
+
# Build @planets entries for each unique date in @weather
|
988
1015
|
@planets.clear
|
989
|
-
|
990
|
-
|
991
|
-
|
1016
|
+
|
1017
|
+
# Collect exactly the dates we need (in first-seen order)
|
1018
|
+
dates = @weather.map { |w| w[:date] }.uniq
|
1019
|
+
|
1020
|
+
dates.each do |date|
|
1021
|
+
# Compute a fresh Ephemeris for that date
|
1022
|
+
ep = Ephemeris.new(date, @lat, @lon, @tz.to_i)
|
1023
|
+
|
1024
|
+
# Start with the printed table + moon phase info
|
992
1025
|
entry = {
|
993
1026
|
table: ep.print,
|
994
|
-
mphase: ep.mphase,
|
995
|
-
mph_s: ep.mph_s
|
1027
|
+
mphase: ep.mphase,
|
1028
|
+
mph_s: ep.mph_s
|
996
1029
|
}
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1030
|
+
|
1031
|
+
# Add rise/set times for each body
|
1032
|
+
Ephemeris::BODY_ORDER.each do |body|
|
1033
|
+
arr = ep.send(body)
|
1034
|
+
entry[:"#{body}_rise"] = arr[5]
|
1035
|
+
entry[:"#{body}_set"] = arr[7]
|
1001
1036
|
end
|
1037
|
+
|
1002
1038
|
@planets[date] = entry
|
1003
1039
|
end
|
1004
1040
|
end
|
1005
1041
|
|
1006
|
-
|
1007
1042
|
def get_events # {{{2
|
1008
1043
|
@events.clear
|
1009
1044
|
uri = URI(
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: astropanel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Geir Isene
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rcurses
|
@@ -28,8 +28,8 @@ description: 'This program shows essential data in order to plan your observatio
|
|
28
28
|
9 days weather forecast, full ephemeris for the Sun, the Moon and all major planets,
|
29
29
|
complete with graphic representation of rise/set times, detailed info for each day
|
30
30
|
with important astronomical events, star chart displayed in the terminal and more.
|
31
|
-
New in 2.0: Full rewrite using rcurses (https://github.com/isene/rcurses). 2.
|
32
|
-
|
31
|
+
New in 2.0: Full rewrite using rcurses (https://github.com/isene/rcurses). 2.6:
|
32
|
+
Bug fix.'
|
33
33
|
email: g@isene.com
|
34
34
|
executables:
|
35
35
|
- astropanel
|