NMEA2000-Code weiterbearbeitet
This commit is contained in:
parent
a0638c76e5
commit
bdbd168123
|
@ -79,11 +79,13 @@ import datetime
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
|
#from .lookup import fluidtype
|
||||||
|
from . import lookup
|
||||||
|
|
||||||
class BoatValue():
|
class BoatValue():
|
||||||
'''
|
"""
|
||||||
Wert mit Datentyp, Einheit, Validekennzeichen und Skalierungsfaktor
|
Wert mit Datentyp, Einheit, Validekennzeichen und Skalierungsfaktor
|
||||||
'''
|
"""
|
||||||
|
|
||||||
placeholder = '---'
|
placeholder = '---'
|
||||||
|
|
||||||
|
@ -299,18 +301,23 @@ class BoatValuePressure(BoatValue):
|
||||||
return self.placeholder
|
return self.placeholder
|
||||||
|
|
||||||
class Tank():
|
class Tank():
|
||||||
|
"""
|
||||||
|
Die Instanz beziegt sich auf den Typ. So kann die Instanz 0
|
||||||
|
für einen Wassertank und einen Dieseltank existieren
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, instance=0):
|
def __init__(self, instance=0):
|
||||||
self.instance = instance
|
|
||||||
self.fluidtype = 1 # water -> lookup
|
self.fluidtype = 1 # water -> lookup
|
||||||
self.volume = None
|
self.instance = instance
|
||||||
self.capacity = None
|
self.level = None # percent
|
||||||
|
self.capacity = None # liter
|
||||||
self.desc = "" # long description
|
self.desc = "" # long description
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
out = f" Tank #{self.instance}"
|
typedesc = lookup.fluidtype[self.fluidtype]
|
||||||
|
out = f" Tank / {typedesc}: #{self.instance}\n"
|
||||||
out += f" Capacity: {self.capacity} l\n"
|
out += f" Capacity: {self.capacity} l\n"
|
||||||
out += f" Fluid level: {self.volume} l\n"
|
out += f" Fluid level: {self.level} %\n"
|
||||||
return out
|
return out
|
||||||
|
|
||||||
class Engine():
|
class Engine():
|
||||||
|
@ -505,9 +512,9 @@ class BoatData():
|
||||||
out += f" Longitude: {self.lon.value}\n"
|
out += f" Longitude: {self.lon.value}\n"
|
||||||
out += f" SOG: {self.sog}\n"
|
out += f" SOG: {self.sog}\n"
|
||||||
for e in self.engine.values():
|
for e in self.engine.values():
|
||||||
print(e)
|
out += str(e)
|
||||||
for t in self.tank.values():
|
for t in self.tank.values():
|
||||||
print(t)
|
out += str(t)
|
||||||
out += " Satellite info\n"
|
out += " Satellite info\n"
|
||||||
for s in self.sat.values():
|
for s in self.sat.values():
|
||||||
out += str(s)
|
out += str(s)
|
||||||
|
|
|
@ -1,32 +1,39 @@
|
||||||
|
"""
|
||||||
|
NMEA2000-Gerät
|
||||||
|
- auf dem Bus erkannte Geräte
|
||||||
|
- für das eigene Gerät steht initUid() zur Verfügung
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Platzhalter WIP
|
|
||||||
- ausprogrammieren nach Bedarf
|
|
||||||
Geräteliste
|
|
||||||
- wird regelmäßig aktualisiert
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import struct
|
import struct
|
||||||
|
from . import lookup
|
||||||
|
|
||||||
class Device():
|
class Device():
|
||||||
|
|
||||||
def __init__(self, address):
|
def __init__(self, address):
|
||||||
#WIP
|
# WIP: Felder können sich noch ändern!
|
||||||
#Felder können sich noch ändern!
|
self.address = address # Kann sich zur Laufzeit ändern
|
||||||
self.address = address
|
|
||||||
self.instance = 0 # default 0
|
|
||||||
self.sysinstance = 0 # used with bridged networks, default 0
|
|
||||||
self.lastseen = time.time()
|
self.lastseen = time.time()
|
||||||
self.uniqueid = None
|
self.lastpinfo = None # Wann letztes Mal Productinfo erhalten?
|
||||||
self.manufacturercode = None
|
self.lastcinfo = None # Wann letztes Mal Configurationinfo erhalten?
|
||||||
|
self.has_cinfo = True # Weitere Abfragen können verhindert werden
|
||||||
|
|
||||||
|
# Device info
|
||||||
|
self.NAME = 0 # Wird über Address-Claim gefüllt
|
||||||
|
self.uniqueid = None # Z.B. aus der Geräteseriennummer abgeleitet
|
||||||
|
self.manufacturercode = 2046 # Open Boat Projects
|
||||||
|
self.instance = 0 # default 0
|
||||||
|
self.instlower = 0 # 3bit, ISO ECU Instance
|
||||||
|
self.instupper = 0 # 5bit, ISO Function Instance
|
||||||
|
self.sysinstance = 0 # used with bridged networks, default 0
|
||||||
self.industrygroup = None
|
self.industrygroup = None
|
||||||
self.name = None # User defined device name
|
|
||||||
self.product = None # Product name
|
|
||||||
self.productcode = None # Product code
|
|
||||||
self.devicefunction = None
|
self.devicefunction = None
|
||||||
self.deviceclass = None
|
self.deviceclass = None
|
||||||
|
|
||||||
|
# Product info
|
||||||
|
self.product = None # Product name
|
||||||
|
self.productcode = None # Product code
|
||||||
self.serial = None
|
self.serial = None
|
||||||
self.modelvers = None # Hardware Version
|
self.modelvers = None # Hardware Version
|
||||||
self.softvers = None # Current Software Version
|
self.softvers = None # Current Software Version
|
||||||
|
@ -34,30 +41,80 @@ class Device():
|
||||||
self.certlevel = None # NMEA2000 Certification Level
|
self.certlevel = None # NMEA2000 Certification Level
|
||||||
self.loadequiv = None # NMEA2000 LEN
|
self.loadequiv = None # NMEA2000 LEN
|
||||||
|
|
||||||
# Configuration Info
|
# Configuration info
|
||||||
self.instdesc1 = None
|
self.instdesc1 = None
|
||||||
self.instdesc2 = None
|
self.instdesc2 = None
|
||||||
self.manufinfo = None
|
self.manufinfo = None
|
||||||
|
|
||||||
def getName(self):
|
# Additional data
|
||||||
# NAME errechnen aus den Claim-Daten
|
self.customname = None # User defined device name
|
||||||
# TODO Das hier ist noch fehlerhaft!
|
|
||||||
|
def _ISOtime(self, epoch):
|
||||||
|
if not epoch:
|
||||||
|
return "n/a"
|
||||||
|
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(epoch))
|
||||||
|
|
||||||
|
def initUid(self):
|
||||||
|
# Initialize unique id from raspi cpu id and return 21bit value
|
||||||
|
with open("/sys/firmware/devicetree/base/serial-number", "r") as f:
|
||||||
|
hexid = f.read().rstrip('\x00')
|
||||||
|
return int(hexid, 16) & 0x001FFFFF # 21bit mask
|
||||||
|
|
||||||
|
def getNAME(self):
|
||||||
|
"""
|
||||||
|
NAME is unique on bus
|
||||||
|
"""
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
data.append((self.deviceclass << 4) | (self.devicefunction & 0x0f))
|
data.extend(struct.pack('<I', (self.uniqueid & 0x001fffff) | (self.manufacturercode << 21)))
|
||||||
data.extend(struct.pack('<L', self.uniqueid))
|
data.append((self.instlower & 0x07) | ((self.instupper & 0x1f) << 3))
|
||||||
data.extend(struct.pack('<L', self.manufacturercode))
|
data.append(self.devicefunction)
|
||||||
data.extend(struct.pack('<L', self.industrygroup))
|
data.append((self.deviceclass & 0x7f) << 1)
|
||||||
|
data.append(0x80 | ((self.industrygroup & 0x07) << 4) | (self.sysinstance & 0x0f))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
out = f"Device: {self.address} : '{self.product}'\n"
|
intNAME = int.from_bytes(self.getNAME())
|
||||||
out += f" Instance: {self.instance}\n"
|
out = f"Device: {self.address} : '{self.product}'\n"
|
||||||
out += f" Product Code: {self.productcode}\n"
|
out += " NAME: {} ({})\n".format(self.getNAME(), intNAME)
|
||||||
out += f" Product: {self.product}\n"
|
out += " last seen: {}\n".format(self._ISOtime(self.lastseen))
|
||||||
out += f" Serial: {self.serial}\n"
|
out += " Device info\n"
|
||||||
out += f" Model Version: {self.modelvers}\n"
|
out += f" Unique ID: {self.uniqueid}\n"
|
||||||
out += f" Software Version: {self.softvers}\n"
|
out += f" Instance: {self.instance} ({self.instupper}/{self.instlower})\n"
|
||||||
out += f" NMEA2000 Version: {self.n2kvers}\n"
|
out += f" System instance: {self.sysinstance}\n"
|
||||||
out += f" Cert-Level: {self.certlevel}\n"
|
try:
|
||||||
out += f" LEN: {self.loadequiv}"
|
devfnname = lookup.devicefunction[self.deviceclass][self.devicefunction]
|
||||||
|
except KeyError:
|
||||||
|
devfnname = "*key error*"
|
||||||
|
out += f" Device function: {devfnname} ({self.devicefunction})\n"
|
||||||
|
try:
|
||||||
|
devclassname = lookup.deviceclass[self.deviceclass]
|
||||||
|
except KeyError:
|
||||||
|
devclassname = "*key error*"
|
||||||
|
out += f" Device class: {devclassname} ({self.deviceclass})\n"
|
||||||
|
try:
|
||||||
|
igrpname = lookup.industrygroup[self.industrygroup]
|
||||||
|
except KeyError:
|
||||||
|
igrpname = "*key error*"
|
||||||
|
out += f" Industry group: {igrpname} ({self.industrygroup})\n"
|
||||||
|
try:
|
||||||
|
manufname = lookup.manufacturer[self.manufacturercode]
|
||||||
|
except KeyError:
|
||||||
|
manufname = "*key error*"
|
||||||
|
out += f" Manufacturer code: {manufname} ({self.manufacturercode})\n"
|
||||||
|
out += " Product info at {}\n".format(self._ISOtime(self.lastpinfo))
|
||||||
|
out += f" Product Code: {self.productcode}\n"
|
||||||
|
out += f" Product: {self.product}\n"
|
||||||
|
out += f" Serial: {self.serial}\n"
|
||||||
|
out += f" Model Version: {self.modelvers}\n"
|
||||||
|
out += f" Software Version: {self.softvers}\n"
|
||||||
|
out += f" NMEA2000 Version: {self.n2kvers}\n"
|
||||||
|
out += f" Cert-Level: {lookup.certlevel[self.certlevel]} ({self.certlevel})\n"
|
||||||
|
out += f" LEN: {self.loadequiv}\n"
|
||||||
|
out += " Configuration info at {}\n".format(self._ISOtime(self.lastcinfo))
|
||||||
|
if self.has_cinfo:
|
||||||
|
out += f" Installation description 1: {self.instdesc1}\n"
|
||||||
|
out += f" Installation description 2: {self.instdesc2}\n"
|
||||||
|
out += f" Manufacturer info: {self.manufinfo}\n"
|
||||||
|
else:
|
||||||
|
out += " not available\n"
|
||||||
return out
|
return out
|
||||||
|
|
|
@ -146,6 +146,7 @@ control = {
|
||||||
deviceclass = {
|
deviceclass = {
|
||||||
0: "Reserved for 2000 Use",
|
0: "Reserved for 2000 Use",
|
||||||
10: "System tools",
|
10: "System tools",
|
||||||
|
11: "WEMA Custom?",
|
||||||
20: "Safety systems",
|
20: "Safety systems",
|
||||||
25: "Internetwork device",
|
25: "Internetwork device",
|
||||||
30: "Electrical Distribution",
|
30: "Electrical Distribution",
|
||||||
|
@ -169,6 +170,8 @@ devicefunction = { # dependent of deviceclass above
|
||||||
10: {130: "Diagnostic",
|
10: {130: "Diagnostic",
|
||||||
140: "Bus Traffic Logger"
|
140: "Bus Traffic Logger"
|
||||||
},
|
},
|
||||||
|
11: {150: "WEMA Fluid level" # Custom?
|
||||||
|
},
|
||||||
20: {110: "Alarm Enunciator",
|
20: {110: "Alarm Enunciator",
|
||||||
130: "Emergency Positon Indicating Radia Beacon (EPIRB)",
|
130: "Emergency Positon Indicating Radia Beacon (EPIRB)",
|
||||||
135: "Man Overboard",
|
135: "Man Overboard",
|
||||||
|
@ -485,7 +488,7 @@ manufacturer = {
|
||||||
1861: "Vector Cantech",
|
1861: "Vector Cantech",
|
||||||
1862: "Yamaha Marine",
|
1862: "Yamaha Marine",
|
||||||
1863: "Faria Instruments",
|
1863: "Faria Instruments",
|
||||||
2001: "Open Boat Projects"
|
2046: "Open Boat Projects"
|
||||||
}
|
}
|
||||||
|
|
||||||
pilotmode = {
|
pilotmode = {
|
||||||
|
|
|
@ -5,8 +5,42 @@ PGNs verarbeiten
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
|
import time
|
||||||
|
from datetime import timedelta, date
|
||||||
|
from . import lookup
|
||||||
|
|
||||||
def parse_126996(buf, source, device):
|
def parse_60928(buf, device):
|
||||||
|
"""
|
||||||
|
Sets data in device and returns the 64bit NAME of device
|
||||||
|
"""
|
||||||
|
device.lastseen = time.time()
|
||||||
|
# 21 bits Unique-ID und 11 bits Manuf.-Code
|
||||||
|
device.uniqueid = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> 3
|
||||||
|
device.manufacturercode = (buf[3] * 256 + buf[2]) >> 5
|
||||||
|
device.instance = buf[4]
|
||||||
|
device.instlower = buf[4] & 0x07
|
||||||
|
device.instupper = buf[4] >> 3
|
||||||
|
device.devicefunction = buf[5]
|
||||||
|
device.deviceclass = (buf[6] & 0x7f) >> 1
|
||||||
|
device.industrygroup = (buf[7] >> 4) & 0x07 # 3bit
|
||||||
|
device.sysinstance = buf[7] & 0x0f # 4bit
|
||||||
|
return struct.unpack_from('>Q', buf, 0)[0]
|
||||||
|
|
||||||
|
def parse_126992(buf, source):
|
||||||
|
# System time
|
||||||
|
print(f"PGN 126992 System time from {source}")
|
||||||
|
sid = buf[0]
|
||||||
|
src = buf[1] & 0x0f
|
||||||
|
dval = date(1970,1,1) + timedelta(days=(buf[3] << 8) + buf[2])
|
||||||
|
secs = struct.unpack_from('<L', buf, 4)[0] * 0.0001
|
||||||
|
print(f" source={source}, date={dval}, secs={secs}, ts={lookup.timesource[src]}")
|
||||||
|
|
||||||
|
def parse_126993(buf, device):
|
||||||
|
# Heartbeat
|
||||||
|
print(f"Heartbeat from {device.address}")
|
||||||
|
print(buf)
|
||||||
|
|
||||||
|
def parse_126996(buf, device):
|
||||||
# Product information
|
# Product information
|
||||||
n2kvers = (buf[0] + buf[1] * 256) / 1000
|
n2kvers = (buf[0] + buf[1] * 256) / 1000
|
||||||
prodcode = buf[2] + buf[3] * 256
|
prodcode = buf[2] + buf[3] * 256
|
||||||
|
@ -20,15 +54,15 @@ def parse_126996(buf, source, device):
|
||||||
softvers = softvers.rstrip(b'\xff')
|
softvers = softvers.rstrip(b'\xff')
|
||||||
modelvers = modelvers.rstrip(b'\xff')
|
modelvers = modelvers.rstrip(b'\xff')
|
||||||
serial = serial.rstrip(b'\xff')
|
serial = serial.rstrip(b'\xff')
|
||||||
# Übertragen in die Geräteliste
|
# Übertragen in die Gerätedaten
|
||||||
devices[source].n2kvers = n2kvers
|
device.n2kvers = n2kvers
|
||||||
devices[source].productcode = prodcode
|
device.productcode = prodcode
|
||||||
devices[source].modelvers = modelvers.decode('ascii').rstrip()
|
device.modelvers = modelvers.decode('ascii').rstrip()
|
||||||
devices[source].softvers = softvers.decode('ascii').rstrip()
|
device.softvers = softvers.decode('ascii').rstrip()
|
||||||
devices[source].product = modelid.decode('ascii').rstrip()
|
device.product = modelid.decode('ascii').rstrip()
|
||||||
devices[source].serial = serial.decode('ascii').rstrip()
|
device.serial = serial.decode('ascii').rstrip()
|
||||||
devices[source].certlevel = buf[132]
|
device.certlevel = buf[132]
|
||||||
devices[source].loadequiv = buf[133]
|
device.loadequiv = buf[133]
|
||||||
|
|
||||||
def parse_126998(buf, source, device):
|
def parse_126998(buf, source, device):
|
||||||
# Configuration information
|
# Configuration information
|
||||||
|
@ -68,9 +102,13 @@ def parse_127257(buf, boatdata):
|
||||||
def parse_127505(buf, boatdata):
|
def parse_127505(buf, boatdata):
|
||||||
# Fluid Level
|
# Fluid Level
|
||||||
instance = buf[0] & 0x0f
|
instance = buf[0] & 0x0f
|
||||||
boatdata.tank[instance].fluidtype = buf[0] >> 4
|
if instance in boatdata.tank:
|
||||||
boatdata.tank[instance].capacity = struct.unpack_from('<L', buf, 2)[0] * 0.1
|
boatdata.tank[instance].fluidtype = buf[0] >> 4
|
||||||
boatdata.tank[instance].volume = struct.unpack_from('<H', buf, 1)[0] * 0.004
|
boatdata.tank[instance].level = struct.unpack_from('<H', buf, 1)[0] * 0.004
|
||||||
|
boatdata.tank[instance].capacity = struct.unpack_from('<L', buf, 3)[0] * 0.1
|
||||||
|
print(boatdata.tank[instance])
|
||||||
|
else:
|
||||||
|
print(f"Tank {instance} not defined!")
|
||||||
|
|
||||||
def parse_127508(buf, boatdata):
|
def parse_127508(buf, boatdata):
|
||||||
# Battery status
|
# Battery status
|
||||||
|
|
|
@ -57,7 +57,7 @@ number_of_pages = 10
|
||||||
start_page = 1
|
start_page = 1
|
||||||
|
|
||||||
[page1]
|
[page1]
|
||||||
type=Voltage
|
type=ApparentWind
|
||||||
|
|
||||||
[page2]
|
[page2]
|
||||||
type=Barograph
|
type=Barograph
|
||||||
|
|
13
obp60.py
13
obp60.py
|
@ -92,7 +92,7 @@ import pages
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
__author__ = "Thomas Hooge"
|
__author__ = "Thomas Hooge"
|
||||||
__copyright__ = "Copyleft 2024, all rights reversed"
|
__copyright__ = "Copyleft 2024-2025, all rights reversed"
|
||||||
__version__ = "0.2"
|
__version__ = "0.2"
|
||||||
__email__ = "thomas@hoogi.de"
|
__email__ = "thomas@hoogi.de"
|
||||||
__status__ = "Development"
|
__status__ = "Development"
|
||||||
|
@ -101,6 +101,10 @@ cfg = {
|
||||||
'cfgfile': 'obp60.conf',
|
'cfgfile': 'obp60.conf',
|
||||||
'imgpath': os.path.join(sys.path[0], 'images'),
|
'imgpath': os.path.join(sys.path[0], 'images'),
|
||||||
'deviceid': 100,
|
'deviceid': 100,
|
||||||
|
'manufcode': 2046, # Open Boat Projects (OBP)
|
||||||
|
'devfunc': 120, # Display
|
||||||
|
'devclass': 120, # Display
|
||||||
|
'industrygroup': 4, # Marine
|
||||||
'gps': False,
|
'gps': False,
|
||||||
'bme280': False
|
'bme280': False
|
||||||
}
|
}
|
||||||
|
@ -495,7 +499,14 @@ if __name__ == "__main__":
|
||||||
#setproctitle("obp60v")
|
#setproctitle("obp60v")
|
||||||
|
|
||||||
shutdown = False
|
shutdown = False
|
||||||
|
|
||||||
owndevice = Device(100)
|
owndevice = Device(100)
|
||||||
|
# Hardcoding device, not intended to change
|
||||||
|
owndevice.manufacturercode = cfg['manufcode']
|
||||||
|
owndevice.industrygroup = cfg['industrygroup']
|
||||||
|
owndevice.deviceclass = cfg['devclass']
|
||||||
|
owndevice.devicefunction = cfg['devfunc']
|
||||||
|
|
||||||
boatdata = BoatData()
|
boatdata = BoatData()
|
||||||
boatdata.addTank(0)
|
boatdata.addTank(0)
|
||||||
boatdata.addEngine(0)
|
boatdata.addEngine(0)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import cairo
|
import cairo
|
||||||
import math
|
import math
|
||||||
from .page import Page
|
from .page import Page
|
||||||
|
@ -6,11 +7,50 @@ class ApparentWind(Page):
|
||||||
|
|
||||||
def __init__(self, pageno, cfg, boatdata):
|
def __init__(self, pageno, cfg, boatdata):
|
||||||
super().__init__(pageno, cfg, boatdata)
|
super().__init__(pageno, cfg, boatdata)
|
||||||
|
self.buttonlabel[1] = 'MODE'
|
||||||
|
self.mode = 'L' # (W)ind (L)ens
|
||||||
|
self.symbol = cairo.ImageSurface.create_from_png(os.path.join(cfg['imgpath'], "front.png"))
|
||||||
|
|
||||||
def draw(self, ctx):
|
def handle_key(self, buttonid):
|
||||||
|
if buttonid == 1:
|
||||||
|
if self.mode == 'W':
|
||||||
|
self.mode = 'L'
|
||||||
|
else:
|
||||||
|
self.mode = 'W'
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def draw_wind(self, ctx):
|
||||||
# Name
|
# Name
|
||||||
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
|
ctx.set_font_size(40)
|
||||||
ctx.set_font_size(60)
|
|
||||||
ctx.move_to(20, 100)
|
ctx.move_to(20, 100)
|
||||||
ctx.show_text("Apparent Wind")
|
ctx.show_text("Apparent Wind")
|
||||||
|
|
||||||
|
def draw_lens(self, ctx):
|
||||||
|
ctx.save()
|
||||||
|
ctx.set_source_surface(self.symbol, 140, 30)
|
||||||
|
ctx.paint()
|
||||||
|
ctx.restore()
|
||||||
|
|
||||||
|
ctx.set_line_width(2)
|
||||||
|
|
||||||
|
# Analoginstrument
|
||||||
|
cx = 200
|
||||||
|
cy = 150
|
||||||
|
r = 135
|
||||||
|
ctx.arc(cx, cy, r, math.radians(110), math.radians(250))
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.arc(cx, cy, r, math.radians(-70), math.radians(70))
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
|
# Windstärke als Digitalwert
|
||||||
|
ctx.select_font_face("DSEG7 Classic")
|
||||||
|
ctx.set_font_size(40)
|
||||||
|
self.draw_text_center(ctx, cx, cy + 80, "14.3", fix1=True)
|
||||||
|
|
||||||
|
def draw(self, ctx):
|
||||||
|
ctx.select_font_face("Ubuntu", cairo.FontSlant.NORMAL, cairo.FontWeight.BOLD)
|
||||||
|
if self.mode == 'W':
|
||||||
|
self.draw_wind(ctx)
|
||||||
|
else:
|
||||||
|
self.draw_lens(ctx)
|
||||||
|
|
|
@ -167,36 +167,67 @@ class Page():
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
ctx.set_source_rgb(0, 0, 0)
|
ctx.set_source_rgb(0, 0, 0)
|
||||||
|
|
||||||
def draw_text_center(self, ctx, x, y, content, rotate=False, baseline=False, fill=False):
|
def draw_text_center(self, ctx, x, y, content, rotate=False, baseline=False, fill=False, fix1=False):
|
||||||
ext = ctx.text_extents(content)
|
"""
|
||||||
|
Korrektur für DSEG7: Die Breite der 1 ist gleich 0.289 * Breite der anderen Ziffern
|
||||||
|
Da der Leerraum bei der Ausgabe mit berücksichtigt wird, muß die tatsächliche
|
||||||
|
Ausgabeposition links von der Mitte sein um (1 - 0.289) * Breite (=0.711)
|
||||||
|
Zusätzlich muß der Abstand zwischen der 1 und dem nachfolgenden Zeichen berücksichtigt
|
||||||
|
werden
|
||||||
|
"""
|
||||||
|
if fix1 and content[0] == '1':
|
||||||
|
print("Fix1")
|
||||||
|
ext1 = ctx.text_extents('1')
|
||||||
|
w1 = 0.289 * ext1.width
|
||||||
|
dx = ext1.width - w1
|
||||||
|
ext = ctx.text_extents(content[1:])
|
||||||
|
else:
|
||||||
|
ext = ctx.text_extents(content)
|
||||||
if fill:
|
if fill:
|
||||||
ctx.set_source_rgb(*self.bgcolor)
|
ctx.set_source_rgb(*self.bgcolor)
|
||||||
xf = x + ext.x_bearing - 2
|
xf = x + ext.x_bearing - 2
|
||||||
yf = y + ext.height / 2 + ext.y_bearing - 2
|
yf = y + ext.height / 2 + ext.y_bearing - 2
|
||||||
wf = ext.width + 4
|
wf = ext.width + 4
|
||||||
|
if fix1:
|
||||||
|
wf += w1
|
||||||
hf = ext.height + 4
|
hf = ext.height + 4
|
||||||
ctx.rectangle(xf, yf, wf, hf)
|
ctx.rectangle(xf, yf, wf, hf)
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
ctx.set_source_rgb(*self.fgcolor)
|
ctx.set_source_rgb(*self.fgcolor)
|
||||||
if rotate:
|
if rotate:
|
||||||
|
w = ext[2]
|
||||||
|
if fix1 and content[0] == '1':
|
||||||
|
w += w1
|
||||||
|
x = x - dx
|
||||||
if baseline:
|
if baseline:
|
||||||
ctx.move_to(x - ext[3] / 2.0, y)
|
ctx.move_to(x - w / 2.0, y)
|
||||||
else:
|
else:
|
||||||
ctx.move_to(x - ext[3] / 2.0, y + ext[2] / 2.0)
|
ctx.move_to(x - w / 2.0, y + ext[2] / 2.0)
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.rotate(1.5 * math.pi)
|
ctx.rotate(1.5 * math.pi)
|
||||||
ctx.show_text(content)
|
ctx.show_text(content)
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
else:
|
else:
|
||||||
|
w = ext.width
|
||||||
|
if fix1 and content[0] == '1':
|
||||||
|
w += w1
|
||||||
|
x = x - dx
|
||||||
if baseline:
|
if baseline:
|
||||||
ctx.move_to(x - ext[2] / 2.0, y)
|
ctx.move_to(x - w / 2.0, y)
|
||||||
else:
|
else:
|
||||||
ctx.move_to(x - ext[2] / 2.0, y + ext[3] / 2.0)
|
ctx.move_to(x - w / 2.0, y + ext[3] / 2.0)
|
||||||
ctx.show_text(content)
|
ctx.show_text(content)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
def draw_text_ralign(self, ctx, x, y, content):
|
def draw_text_ralign(self, ctx, x, y, content, fix1=False):
|
||||||
ext = ctx.text_extents(content)
|
if fix1 and content[0] == '1':
|
||||||
ctx.move_to(x - ext[2], y)
|
w1 = ctx.text_extents('1')[2] * 0.289
|
||||||
|
ext = ctx.text_extents(content[1:])
|
||||||
|
w = ext[2] + w1
|
||||||
|
x = x - dx
|
||||||
|
else:
|
||||||
|
ext = ctx.text_extents(content)
|
||||||
|
w = ext[2]
|
||||||
|
ctx.move_to(x - w, y)
|
||||||
ctx.show_text(content)
|
ctx.show_text(content)
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
Loading…
Reference in New Issue