208 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
| """
 | |
| 
 | |
| Tide Vorausschau
 | |
|  
 | |
| """
 | |
| 
 | |
| import cairo
 | |
| from .page import Page
 | |
| from datetime import datetime
 | |
| 
 | |
| class Tide(Page):
 | |
| 
 | |
|     def __init__(self, pageno, cfg, appdata, boatdata):
 | |
|         super().__init__(pageno, cfg, appdata, boatdata)
 | |
| 
 | |
|         self.buttonlabel[1] = 'MODE'
 | |
|         self.mode = 'N' # (N)ormal, (C)onfiguration
 | |
| 
 | |
|         self.station = "f3c6ee73-5561-4068-96ec-364016e7d9ef" # Schulau
 | |
|         self.pegel = 'List, Sylt'
 | |
|         self.app.web.set_pegel(self.pegel)
 | |
|         self.app.web.refresh()
 | |
| 
 | |
|         # Steuerung der Stationsliste
 | |
|         self.list_max = 10
 | |
|         self.list_top = 0
 | |
|         self.list_ix = 0
 | |
|         self.list_pegel = self.pegel
 | |
|         self.list_count = len(self.app.web.pegeldata)
 | |
| 
 | |
|     def handle_key(self, buttonid):
 | |
|         if buttonid == 1:
 | |
|             if self.mode == 'N':
 | |
|                 self.mode = 'C'
 | |
|                 self.buttonlabel[3] = '#UP'
 | |
|                 self.buttonlabel[4] = '#DOWN'
 | |
|                 self.buttonlabel[5] = 'SET'
 | |
|             else:
 | |
|                 self.mode = 'N'
 | |
|                 self.buttonlabel[3] = '#PREV'
 | |
|                 self.buttonlabel[4] = '#NEXT'
 | |
|                 self.buttonlabel[5] = ''
 | |
|             return True
 | |
|         if self.mode == 'C':
 | |
|             if buttonid == 3:
 | |
|                 # Up
 | |
|                 self.list_ix -= 1
 | |
|                 if self.list_ix < self.list_top:
 | |
|                     self.list_top -= 1
 | |
|             elif buttonid == 4:
 | |
|                 # Down
 | |
|                 self.list_ix += 1
 | |
|                 if self.list_ix > self.list_top + self.list_max:
 | |
|                     self.list_top += 1
 | |
|             elif buttonid == 5:
 | |
|                 # Set
 | |
|                 print(self.list_pegel)
 | |
|                 self.pegel = self.list_pegel
 | |
|                 self.app.web.set_pegel(self.list_pegel)
 | |
|                 self.app.web.refresh()
 | |
|             return True
 | |
|         return False
 | |
| 
 | |
|     def draw_config(self, ctx):
 | |
|         # Auswahl
 | |
|         # - Station
 | |
|         # - Zeitraum
 | |
|         #   
 | |
|         ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
 | |
|         ctx.set_font_size(20)
 | |
| 
 | |
|         ctx.move_to(2, 50)
 | |
|         ctx.show_text("Tide configuration")
 | |
| 
 | |
|         y = 80
 | |
|         dy = 20
 | |
|         ctx.set_font_size(20)
 | |
|         i = 0
 | |
|         ix = -1
 | |
|         for pd in self.app.web.pegeldata:
 | |
|             ix += 1
 | |
|             if ix < self.list_top:
 | |
|                 continue
 | |
|             ctx.move_to(20, y + dy * i)
 | |
|             ctx.show_text(pd)
 | |
|             self.list_pegel = pd
 | |
|             if self.list_ix == ix:
 | |
|                 ctx.show_text(' X')
 | |
|             i += 1
 | |
|             if self.pegel == pd:
 | |
|                 ctx.show_text(' *')
 | |
|             if ix > self.list_top + self.list_max - 1:
 | |
|                 break
 | |
| 
 | |
|     def draw_normal(self, ctx):
 | |
|         # Title
 | |
|         ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
 | |
|         ctx.set_font_size(24)
 | |
|         ctx.move_to(8, 40)
 | |
|         ctx.show_text("Tide prediction")
 | |
|         ctx.set_font_size(10)
 | |
| 
 | |
|         # Daten holen
 | |
|         self.app.web.set_timestamp(2, 48)
 | |
|         ymin, ymax = self.app.web.get_tide_minmax()
 | |
|         rawdata = self.app.web.get_tide()
 | |
| 
 | |
|         # scale_y_step
 | |
|         scale_y_step = 50
 | |
|         ymin = min(ymin, self.app.web.tide['MNW']) - 10
 | |
|         ymin = (ymin // scale_y_step - 1) * scale_y_step
 | |
|         ymax = max(ymax, self.app.web.tide['MHW']) + 10
 | |
|         ymax = (ymax // scale_y_step + 1) * scale_y_step
 | |
|         #self.tide['warning'] = wvdata["warning"]
 | |
|         #self.tide['forecast_ts'] = wvdata["creation_forecast"]
 | |
| 
 | |
|         x0 = 40 # links unten
 | |
|         y0 = 250
 | |
|         x1 = 380 # rechts oben
 | |
|         y1 = 60
 | |
| 
 | |
|         ctx.set_line_width(1)
 | |
|         ctx.set_dash((2, 2), 0)
 | |
|         y = (self.app.web.tide['MNW'] - ymin) / (ymax - ymin) * (y0 - y1)
 | |
|         ctx.move_to(x0 - 8, y0 - y)
 | |
|         ctx.line_to(x1 + 8, y0 - y)
 | |
|         y = (self.app.web.tide['MHW'] - ymin) / (ymax - ymin) * (y0 - y1)
 | |
|         ctx.move_to(x0 - 8, y0 - y)
 | |
|         ctx.line_to(x1 + 8, y0 - y)
 | |
|         ctx.stroke()
 | |
|         ctx.set_dash([])
 | |
| 
 | |
|         ctx.set_font_size(16)
 | |
|         ctx.set_line_width(2)
 | |
| 
 | |
|         ctx.move_to(220, 40)
 | |
|         self.draw_text_ralign(ctx, 392, 36, self.app.web.tide['station'])
 | |
| 
 | |
|         ctx.move_to(8, 50)
 | |
|         calc_ts = datetime.fromisoformat(self.app.web.tide['forecast_ts'])
 | |
|         self.draw_text_ralign(ctx, 392, 52, "calc: " + calc_ts.strftime('%H:%M'))
 | |
|         #self.tide['area'] = wvdata["area"]
 | |
| 
 | |
|         # X-Achse
 | |
|         ctx.move_to(x0 + 0.5, y0 + 0.5)
 | |
|         ctx.line_to(x0 + 0.5, y1 + 0.5)
 | |
|         ctx.stroke()
 | |
| 
 | |
|         # Pfeilspitze Y
 | |
|         ctx.move_to(x1 + 0.5, y0 + 0.5 - 4)
 | |
|         ctx.line_to(x1 + 0.5 + 12, y0 + 0.5)
 | |
|         ctx.line_to(x1 + 0.5, y0 + 0.5 + 4)
 | |
|         ctx.close_path()
 | |
|         ctx.fill()
 | |
| 
 | |
|         # Pfeilspitze Y
 | |
|         ctx.move_to(x0 + 0.5 - 4, y1 + 0.5)
 | |
|         ctx.line_to(x0 + 0.5, y1 + 0.5 - 12)
 | |
|         ctx.line_to(x0 + 0.5 + 4, y1 + 0.5)
 | |
|         ctx.close_path()
 | |
|         ctx.fill()
 | |
| 
 | |
|         # self.draw_text_center(ctx, x0 - 20, y0 + (y1 -y0) / 2, "Höhe, cm", rotate=True)
 | |
|         self.draw_text_center(ctx, 60, 150, "height, cm", rotate=True)
 | |
|         #self.draw_text_center(ctx, 100, 100, "Höhe, cm", rotate=False)
 | |
|         #ctx.move_to(90, 90) # Rotationsursprung
 | |
|         #ctx.line_to(110, 110)
 | |
|         #ctx.move_to(90, 110)
 | |
|         #ctx.line_to(110, 90)
 | |
|         #ctx.stroke()
 | |
| 
 | |
|         # Y-Achse
 | |
|         ctx.move_to(x0 + 0.5, y0 + 0.5)
 | |
|         ctx.line_to(x1 + 0.5, y0 + 0.5)
 | |
|         self.draw_text_center(ctx, x0 + (x1 - x0) / 2, y0 + 12, "time, h")
 | |
|         ctx.stroke()
 | |
| 
 | |
|         ctx.move_to(x0 - 32, y0 + 8)
 | |
|         ctx.show_text(str(ymin))
 | |
| 
 | |
|         ctx.move_to(x0 - 32, y1 + 8)
 | |
|         ctx.show_text(str(ymax))
 | |
| 
 | |
|         # Anzahl Meßwerte für die X-Achse
 | |
|         #ctx.move_to(x0 + 16, y0 + 16)
 | |
|         #ctx.show_text(f"n = {len(rawdata)}")
 | |
| 
 | |
|         dx = (x1 - x0) / len(rawdata)
 | |
|         x = x0
 | |
|         prev_valid = False
 | |
|         for val in rawdata:
 | |
|             if val is not None:
 | |
|                 y = (val - ymin) / (ymax - ymin) * (y0 - y1)
 | |
|                 if prev_valid:
 | |
|                     ctx.line_to(x, y0 - y)
 | |
|                 else:
 | |
|                     ctx.move_to(x, y0 - y)
 | |
|                 prev_valid = True
 | |
|             else:
 | |
|                 prev_valid = False
 | |
|             x += dx
 | |
| 
 | |
|     def draw(self, ctx):
 | |
|         if self.mode == 'N':
 | |
|             self.draw_normal(ctx)
 | |
|         else:
 | |
|             self.draw_config(ctx)
 |