""" Tracker mit MQTT client Es gibt zwei Modi: Track und Race A) Track: Es wird nur der Track gesended / aufgezeichnet B) Race: Es werden zusätzlich Regattadaten angezeigt, das beinhaltet die Auswahl einer Regatta, das Teilnehmen, das Aufgeben und die Signalisierung vor und während einer Wettfahrt. Das Tracking kann über eine Taste ein- und ausgeschaltet werden. Um versehentliches Umschalten zu vermeiden ist eine Nachfrage integriert. - currentry only Ragatta hero supported Behandlung von Verbindungsabbrüchen: - on_disconnect """ import os import cairo from .page import Page from cfgmenu import Menu class Tracker(Page): def __init__(self, pageno, cfg, appdata, boatdata): super().__init__(pageno, cfg, appdata, boatdata) self.bv_lat = boatdata.getRef("LAT") self.bv_lon = boatdata.getRef("LON") self.bv_sog = boatdata.getRef("SOG") self.races = None self.raceid = None # Ausgewählte Regatta self.menupos = 0 self.buttonlabel[1] = 'MODE' self.mode = 'N' # (N)ormal, (C)onfiguration # Flaggengröße: 96 x 64 Pixel self.flagpos = ((208, 140), (308, 140), (208, 210), (308, 210)) # Flaggen laden flag = ('alpha', 'answer', 'black', 'blue', 'charlie', 'class', 'finish', 'hotel', 'india', 'november', 'orange', 'papa', 'repeat_one', 'sierra', 'start', 'uniform', 'xray', 'yankee', 'zulu') # Mapping self.flagmap = { 3: 'blue', # 8: 'sierra', # Bahnverkürzung 9: 'november', # Abbruch 10: 'yankee', # Schwimmwesten 11: 'repeat_one', # Rückruf 12: 'answer', # Startverschiebung 14: 'start', 15: 'class', # Klassenflagge 100: 'papa', # Vorbereitung, Frühstart: Zurückfallen über Startlinie 101: 'india', # Vorbereitung, Frühstart: Starttonne umrunden 102: 'zulu', # Frühstart: 20%-Strafe 103: 'uniform', # Frühstart: Disqualifikation, Wiederholung erlaubt 104: 'black' # Frühstart: Disqualifikation, Wiederholung nicht erlaubt } self.sym_flag = {} for f in flag: flagfile = os.path.join(cfg['imgpath'], 'flags', f + '.png') self.sym_flag[f] = cairo.ImageSurface.create_from_png(flagfile) self._menu = Menu("Regattas", 200, 250) self._menu.setItemDimension(120, 20) def handle_key(self, buttonid): if buttonid == 1: # Modus umschalten if self.mode == 'N': self.mode = 'C' self.buttonlabel[2] = '#UP' self.buttonlabel[3] = '#DOWN' self.buttonlabel[4] = 'SET' if self.appdata.track.is_active(): self.buttonlabel[5] = 'OFF' else: self.buttonlabel[5] = 'ON' else: self.mode = 'N' self.buttonlabel[2] = '' self.buttonlabel[3] = '#PREV' self.buttonlabel[4] = '#NEXT' self.buttonlabel[5] = '' return True elif buttonid == 2: if self.mode == 'C': # Up if self.menupos > 1: self.menupos -= 1 else: self.menupos = len(self.races) return True elif buttonid == 3: if self.mode == 'C': # Down if self.menupos < len(self.races): self.menupos += 1 else: self.menupos = 1 return True elif buttonid == 4: if self.mode == 'C': # Set / Select regatta if self.menupos > 0: self.raceid = self.races[self.menupos - 1] # Nullbasiert self.appdata.track.hero_raceid = self.raceid print(f"Selected race '{self.raceid}'") return True elif buttonid == 5: if self.mode == 'C': # Tracking ein/-ausschalten if self.appdata.track.is_active(): self.appdata.track.set_active(False) self.buttonlabel[5] = 'ON' else: self.appdata.track.set_active(True) self.buttonlabel[5] = 'OFF' else: self.appdata.frontend.flashled.setColor('yellow') #self.appdata.frontend.flashled.switchOn(4) self.appdata.frontend.flashled.doFlash(2) return True return False def draw_normal(self, ctx): # Name #ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) #ctx.set_font_size(32) #ctx.move_to(20, 80) #ctx.show_text("Tracker") ctx.select_font_face("DSEG7 Classic") ctx.set_font_size(80) if self.appdata.track.is_active(): if self.appdata.track.hero_racestatus: counter = self.appdata.track.hero_racestatus['time'] minutes, seconds = divmod(abs(counter), 60) if counter < 0: ctx.move_to(16, 120) ctx.show_text(f"-{minutes:02d}:{seconds:02d}") else: ctx.move_to(28, 120) ctx.show_text(f"{minutes:03d}:{seconds:02d}") else: ctx.move_to(48, 120) ctx.show_text("--:--") else: ctx.move_to(100, 120) ctx.show_text("off") x0 = 8 x1 = 104 y0 = 150 ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.set_font_size(16) ctx.move_to(x0, y0) ctx.show_text("Type: ") ctx.move_to(x1, y0) ctx.show_text(self.appdata.track.ttype) ctx.move_to(x0, y0 + 16) ctx.show_text("Regatta") ctx.move_to(x1, y0 + 16) ctx.show_text(self.appdata.track.hero_raceid or '[not selected]') ctx.move_to(x0, y0 + 32) ctx.show_text("Course") ctx.move_to(x1, y0 + 32) if self.appdata.track.hero_orgstatus and self.appdata.track.hero_raceid: ctx.show_text(self.appdata.track.hero_orgstatus['races'][self.appdata.track.hero_raceid]['courseid']) else: ctx.show_text('[not selected]') ctx.move_to(x0, y0 + 48) ctx.show_text("Latitude") ctx.move_to(x1, y0 + 48) ctx.show_text(self.bv_lat.format()) ctx.move_to(x0, y0 + 64) ctx.show_text("Longitude") ctx.move_to(x1, y0 + 64) ctx.show_text(self.bv_lon.format()) ctx.move_to(x0, y0 + 80) ctx.show_text("Speed") ctx.move_to(x1, y0 + 80) ctx.show_text(self.bv_sog.format()) # Flaggen if self.appdata.track.hero_racestatus: pos = 0 for f in self.appdata.track.hero_racestatus['flags']: if f in self.flagmap: # TODO Context save/restore erforderlich? ctx.save() ctx.set_source_surface(self.sym_flag[self.flagmap[f]], *self.flagpos[pos]) ctx.paint() ctx.restore() pos += 1 def draw_config(self, ctx): ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD) ctx.set_font_size(24) ctx.move_to(4, 42) ctx.show_text("Tracker configuration") x0 = 8 x1 = 88 y0 = 96 ctx.set_font_size(20) ctx.move_to(x0, 75) ctx.show_text("Boat data") ctx.set_font_size(16) ctx.move_to(x0, y0) ctx.show_text("Name") ctx.move_to(x1, y0) ctx.show_text(self.cfg['boat']['name']) ctx.move_to(x0, y0 + 16) ctx.show_text("Class") ctx.move_to(x1, y0 + 16) ctx.show_text(self.cfg['boat']['class']) ctx.move_to(x0, y0 + 32) ctx.show_text("Handicap") ctx.move_to(x1, y0 + 32) ctx.show_text(str(self.cfg['boat']['handicap'])) ctx.move_to(x0, y0 + 48) ctx.show_text("Club") ctx.move_to(x1, y0 + 48) ctx.show_text(self.cfg['boat']['club']) ctx.move_to(x0, y0 + 64) ctx.show_text("Sailno.") ctx.move_to(x1, y0 + 64) ctx.show_text(self.cfg['boat']['sailno']) x0 = 208 x1 = 272 ctx.set_font_size(20) ctx.move_to(x0, 75) ctx.show_text("Tracker info") ctx.set_font_size(16) ctx.move_to(x0, y0) ctx.show_text("Type: ") ctx.show_text(self.appdata.track.ttype) ctx.move_to(x0, y0 + 16) ctx.show_text("Status") ctx.move_to(x0, y0 + 32) ctx.show_text("Org.") ctx.move_to(x0, y0 + 48) ctx.show_text("Team") # Mögliche Regatten self.races = self.appdata.track.hero_get_races() if len(self.races) == 1: self.raceid = self.races[0] self.menupos = 1 x = 208 y = 180 ctx.set_font_size(20) ctx.move_to(x, y) ctx.show_text("Select Regatta") ctx.set_font_size(16) y += 4 if self.menupos > len(self.races): # Nichts auswählen self.menupos = 0 self.raceid = None i = 0 for r in self.races: i += 1 if r == self.raceid: r += '*' self.draw_text_boxed(ctx, x, y, 180, 20, r, (self.menupos == i)) y += 20 if i == 0: ctx.move_to(x, y + 20) ctx.show_text("[ none ]") def draw(self, ctx): if self.mode == 'N': self.draw_normal(ctx) else: self.draw_config(ctx)