241 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
| """
 | |
| 
 | |
| Uhr
 | |
| 
 | |
| TODO: Zeitzone anzeigen. Abhängig von Lat, Lon
 | |
| 
 | |
|  Es sollen verschiedene Modi unterstützt werden
 | |
|  - Analoguhr
 | |
|  - Digitaluhr
 | |
|  - Regattauhr / -timer
 | |
| 
 | |
| """
 | |
| 
 | |
| import os
 | |
| import cairo
 | |
| import math
 | |
| from .page import Page
 | |
| from datetime import datetime, timezone, timedelta
 | |
| import astral
 | |
| 
 | |
| class Clock(Page):
 | |
| 
 | |
|     def __init__(self, pageno, cfg, appdata, boatdata):
 | |
|         super().__init__(pageno, cfg, appdata, boatdata)
 | |
|         self.buttonlabel[1] = 'MODE'
 | |
|         self.buttonlabel[2] = 'TZ'
 | |
|         self.mode = ('A', 'D', 'T') # (A)nalog (D)igital (T)imer
 | |
|         self.modeindex = 0
 | |
|         self.utc = True
 | |
|         self.tzoffset = cfg['tzoffset']
 | |
|         self.bv_lat = boatdata.getRef("LAT")
 | |
|         self.bv_lon = boatdata.getRef("LON")
 | |
|         # Eine beliebiger Ort damit irgendetwas gesetzt ist
 | |
|         self.set_location('Norderstedt', 'Germany', 53.710105, 10.0574378)
 | |
|         self.bgimg = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "unknown.png"))
 | |
| 
 | |
|     def handle_key(self, buttonid):
 | |
|         if buttonid == 1:
 | |
|             if self.modeindex < len(self.mode) - 1:
 | |
|                 self.modeindex += 1
 | |
|             else:
 | |
|                 self.modeindex = 0
 | |
|             return True
 | |
|         if buttonid == 2:
 | |
|             self.utc = not self.utc
 | |
|             return True
 | |
|         return False
 | |
| 
 | |
|     def set_location(self, city, country, lat, lon, tz='UTC'):
 | |
|         try:
 | |
|             # Astral ab Debian 13
 | |
|             self.location = astral.LocationInfo((city, country, lat, lon, tz))
 | |
|         except AttributeError:
 | |
|             # Astral bis Debian 12 (Version 1.6.1)
 | |
|             self.location = astral.Location((city, country, lat, lon, tz))
 | |
|             self.location.astral = astral.Astral()
 | |
| 
 | |
|     def display_new(self):
 | |
|         """
 | |
|         Position für Sonnenauf- und Untergang neu ermitteln
 | |
|         Machen wir hier einmal je Seitenaufruf, besser wäre es
 | |
|         in regelmäßigen Zeitabständen. Das kann dann später implementiert
 | |
|         werden.
 | |
|         """
 | |
|         if self.bv_lat.valid and self.bv_lon.valid:
 | |
|             self.set_location('Ship', 'World', self.bv_lat.getValue, self.bv_lon.getValue, 'UTC')
 | |
| 
 | |
|     def draw(self, ctx):
 | |
|         ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
 | |
| 
 | |
|         # akuellen Modus anzeigen
 | |
|         if self.mode[self.modeindex] == 'A':
 | |
|             self.draw_analog(ctx)
 | |
|         elif self.mode[self.modeindex] == 'D':
 | |
|             self.draw_digital(ctx)
 | |
|         else:
 | |
|             self.draw_timer(ctx)
 | |
| 
 | |
|     def draw_digital(self, ctx):
 | |
| 
 | |
|         # TODO
 | |
|         # Sonnenauf- und Untergang
 | |
|         # Zeitzone
 | |
| 
 | |
|         ts = datetime.now()
 | |
| 
 | |
|         ctx.set_font_size(20)
 | |
|         ctx.move_to(10, 60)
 | |
|         ctx.show_text("RTC")
 | |
| 
 | |
|         ctx.select_font_face("DSEG7 Classic")
 | |
|         ctx.set_font_size(72)
 | |
|         # Zentrieren funktioniert nicht richtig, da der Leerraum vor der "1"
 | |
|         # mitgerechnet wird. Dafür muß ggf. der Zeichensatz angepaßt werden.
 | |
|         # self.draw_text_center(ctx, 200, 150, ts.strftime("%H:%M:%S"))
 | |
|         ctx.move_to(0, 200)
 | |
|         ctx.show_text(ts.strftime("%-H:%M:%S"))
 | |
| 
 | |
|     def draw_timer(self, ctx):
 | |
|         ts = datetime.now()
 | |
|         ctx.set_font_size(24)
 | |
|         ctx.move_to(10, 50)
 | |
|         ctx.show_text("Race Timer")
 | |
|         ctx.select_font_face("AtariST8x16SystemFont")
 | |
|         ctx.set_font_size(16)
 | |
|         self.draw_text_center(ctx, 200, 230, "Here be dragons")
 | |
|         ctx.save()
 | |
|         ctx.set_source_surface(self.bgimg, 140, 80)
 | |
|         ctx.paint()
 | |
|         ctx.restore()
 | |
| 
 | |
|     def draw_analog(self, ctx):
 | |
| 
 | |
|         ts = datetime.now()
 | |
|         if self.utc:
 | |
|             pass
 | |
|         # Location ist in UTC definiert
 | |
|         sunrise = self.location.sunrise(ts)
 | |
|         sunset = self.location.sunset(ts)
 | |
|         if not self.utc:
 | |
|             td = timedelta(hours=self.tzoffset)
 | |
|             sunrise += td
 | |
|             sunset += td
 | |
| 
 | |
|         # Wochentag
 | |
|         # ts.strftime('%a')
 | |
| 
 | |
|         # Werte in den Ecken der Uhr 
 | |
|         ctx.set_font_size(24)
 | |
|         ctx.move_to(10, 220)
 | |
|         ctx.show_text("Time")
 | |
|         ctx.move_to(10, 95)
 | |
|         ctx.show_text("Date")
 | |
|         ctx.move_to(335, 95)
 | |
|         ctx.show_text("SunR")
 | |
|         ctx.move_to(335, 220)
 | |
|         ctx.show_text("SunS")
 | |
|         ctx.stroke()
 | |
| 
 | |
|         ctx.set_font_size(16)
 | |
| 
 | |
|         # Datum links oben
 | |
|         ctx.move_to(10, 65)
 | |
|         ctx.show_text(ts.strftime("%d.%m.%Y"))
 | |
|         # Uhrzeit links unten
 | |
|         ctx.move_to(10, 250)
 | |
|         ctx.show_text(ts.strftime("%H:%M"))
 | |
|         # Sonnenaufgang rechts oben
 | |
|         ctx.move_to(335, 65)
 | |
|         ctx.show_text(sunrise.strftime("%H:%M"))
 | |
|         # Sonnenuntergang rechts unten
 | |
|         ctx.move_to(335, 250)
 | |
|         ctx.show_text(sunset.strftime("%H:%M"))
 | |
|         ctx.stroke()
 | |
| 
 | |
|         # Horizontale Trennlinien
 | |
|         ctx.rectangle(0, 149, 60, 3)
 | |
|         ctx.rectangle(340, 149, 60, 3)
 | |
|         ctx.fill()
 | |
| 
 | |
|         # Uhr
 | |
|         cx = 200
 | |
|         cy = 150
 | |
|         r = 110
 | |
|         ctx.arc(cx, cy, r + 10, 0, 2*math.pi)
 | |
|         ctx.arc(cx, cy, r + 7, 0, 2*math.pi)
 | |
|         ctx.stroke()
 | |
| 
 | |
|         ctx.set_font_size(20)
 | |
|         self.draw_text_center(ctx, cx, cy-40, 'UTC' if self.utc else 'LOT')
 | |
| 
 | |
|         ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
 | |
|         ctx.set_font_size(24)
 | |
| 
 | |
|         for i in range(360):
 | |
|             x = cx + (r - 30) * math.sin(i/180*math.pi)
 | |
|             y = cy - (r - 30) * math.cos(i/180*math.pi)
 | |
| 
 | |
|             char = ""
 | |
|             if i == 0:
 | |
|                 char = "12"
 | |
|             elif i == 90:
 | |
|                 char = "3"
 | |
|             elif i == 180:
 | |
|                 char = "6"
 | |
|             elif i == 270:
 | |
|                 char = "9"
 | |
| 
 | |
|             if i % 90 == 0:
 | |
|                 #ctx.move_to(x, y)
 | |
|                 self.draw_text_center(ctx, x, y, char)
 | |
|                 #ctx.stroke()
 | |
| 
 | |
|             ctx.set_line_width(3.0)
 | |
|             if i % 6 == 0:
 | |
|                 if i % 30 == 0:
 | |
|                     x0 = cx + (r - 10) * math.sin(i/180*math.pi)
 | |
|                     y0 = cy - (r - 10) * math.cos(i/180*math.pi)
 | |
|                     x1 = cx + (r + 10) * math.sin(i/180*math.pi)
 | |
|                     y1 = cy - (r + 10) * math.cos(i/180*math.pi)
 | |
|                     ctx.move_to(x0, y0)
 | |
|                     ctx.line_to(x1, y1)
 | |
|                     ctx.stroke()
 | |
|                 else:
 | |
|                     x = cx + r * math.sin(i/180*math.pi)
 | |
|                     y = cy - r * math.cos(i/180*math.pi)
 | |
|                     ctx.arc(x, y, 2, 0, 2*math.pi)         
 | |
|                     ctx.fill()
 | |
|         
 | |
|         # Stundenzeiger
 | |
|         p = ((cx - 2, cy - (r - 50)), (cx + 2, cy - (r - 50)), (cx + 6, cy + 16), (cx - 6, cy + 16))
 | |
|         angle_h = (ts.hour % 12  + ts.minute / 60) * 30
 | |
|         zeiger = self.rotate((cx, cy), p, angle_h)
 | |
|         ctx.move_to(*zeiger[0])
 | |
|         for point in zeiger[1:]:
 | |
|             ctx.line_to(*point)
 | |
|         ctx.fill()
 | |
| 
 | |
|         # Minutenzeiger
 | |
|         p = ((cx - 1, cy - (r - 15)), (cx + 1, cy - (r - 15)), (cx + 6, cy + 20), (cx - 6, cy + 20))
 | |
|         angle_m = ts.minute * 6
 | |
|         zeiger = self.rotate((cx, cy), p, angle_m)
 | |
|         ctx.move_to(*zeiger[0])
 | |
|         for point in zeiger[1:]:
 | |
|             ctx.line_to(*point)
 | |
|         ctx.fill()
 | |
| 
 | |
|         # Zentraler Kreis
 | |
|         ctx.set_source_rgb(0, 0, 0)
 | |
|         ctx.arc(cx, cy, 12, 0, 2*math.pi)
 | |
|         ctx.fill()
 | |
| 
 | |
|         # Wozu dieses?
 | |
|         ctx.set_source_rgb(0.86, 0.86, 0.86)
 | |
|         ctx.arc(cx, cy, 10, 0, 2*math.pi)
 | |
|         ctx.fill()
 | |
| 
 | |
|         ctx.set_source_rgb(0, 0, 0)
 | |
|         ctx.arc(cx, cy, 2, 0, 2*math.pi)
 | |
|         ctx.fill()
 |