def _create(self): logging.info('Creating pi3d components') self.DISPLAY = pi3d.Display.create( frames_per_second=Constants.FPS, background=Constants.BACKGROUND_COLOR) self.CAMERA = pi3d.Camera(is_3d=False) self.SHADER = pi3d.Shader("blend_new") self.SLIDE = pi3d.Sprite(camera=self.CAMERA, w=self.DISPLAY.width, h=self.DISPLAY.height, z=5.0) self.SLIDE.set_shader(self.SHADER) self.SLIDE.unif[47] = Constants.EDGE_ALPHA self.FONT = pi3d.Font(Constants.FONT_FILE, codepoints=Constants.CODEPOINTS, grid_size=7, shadow_radius=4.0, shadow=(0, 0, 0, 128)) self.TEXT = pi3d.PointText(self.FONT, self.CAMERA, max_chars=200, point_size=50) self.TEXTBLOCK = pi3d.TextBlock(x=-self.DISPLAY.width * 0.5 + 50, y=-self.DISPLAY.height * 0.4, z=0.1, rot=0.0, char_count=199, size=0.99, text_format="{}".format(1), spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) self.TEXT.add_text_block(self.TEXTBLOCK)
def init(): global text6,actualy,displayheight text6 = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=1000, point_size=128) count = 0 mystring = '' actualy = 0 for e in list(gcal.timeline.start_after(arrow.now().floor('day'))): if count < 5: size = 0.79 titles = pi3d.TextBlock(-390, ((displayheight/2) + actualy - (graphics.pointFont.height*size*0.5)), 0.1, 0.0, 30 ,text_format= e.begin.humanize(locale='de_de').title(), size=size, spacing="F", space=0.02, colour=(1,0,0,1)) text6.add_text_block(titles) actualy -= titles.size * graphics.pointFont.height size = 0.29 date = pi3d.TextBlock(-380, ((displayheight/2) + actualy - (graphics.pointFont.height*size*0.5)), 0.1, 0.0, 12 ,text_format= '(' + e.begin.format('DD.MM.YYYY') + ')', size=size,spacing="F", space= 0.02, colour=(1,1,1,1)) text6.add_text_block(date) actualy -= date.size * graphics.pointFont.height size = 0.4 width = 0 subtext = '' actualword = '' g_scale = float(text6.point_size) / graphics.pointFont.height for c in e.name: width += graphics.pointFont.glyph_table[c][0] * g_scale * size actualword += c if c in (' ','-',',','.','+',':'): subtext += actualword actualword = '' if width > 730: event = pi3d.TextBlock(-350, (displayheight/2) + actualy - (graphics.pointFont.height*size*0.5), 0.1, 0.0, 40, text_format = subtext, size=size,spacing="F",space =0.02,colour=(1,1,1,1)) text6.add_text_block(event) subtext = '' width = 0 actualy -= event.size * graphics.pointFont.height if (subtext != '') or (actualword != ''): event = pi3d.TextBlock(-350, (displayheight/2) + actualy - (graphics.pointFont.height*size*0.5), 0.1, 0.0, 40,text_format = subtext + actualword, size=size,spacing="F",space = 0.02,colour=(1,1,1,1)) text6.add_text_block(event) actualy -= event.size * graphics.pointFont.height actualy -= 20 count+=1 else: break
from pkg_resources import resource_filename from .. import config from ..core import peripherals from ..core import graphics from ..subslides import wifisetup try: unichr except NameError: unichr = chr chars = [] chars.append( pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=220, point_size=128)) chars.append( pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=220, point_size=128)) chars.append( pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=220, point_size=128)) keyboardslide = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=220, point_size=128)
def __init__(self, x_values, y_values, width, height, font, title=None, line_width=2, axes_desc=None, legend=None, xpos=0, ypos=0, xmin=None, xmax=None, ymin=None, ymax=None, camera=None, shader=None): ''' Arguments: *x_values* 1D numpy array *y_values* 1 or 2D numpy array with size same as x_values in 2nd D draws a line graph or 3D numpy array with size same as x along axis=1 and last axis has 2 values. In this case the graph is drawn as vertical lines *width, height* as expected *font* pi3d.Font instance *title, line_width* as expected *axes_desc* tuple -> (x.axis.desc, y.axis.desc) *legend* tuple -> (y0.desc, y1.desc, y2.desc...) *xpos, ypos* offset relative to origin of display (centre) *xmin, xmax, ymin, ymax* override sampled values from init data *camera* if no other Shape to be drawn then a 2D Camera can be created here *shader* if no other Shape uses mat_flat shader then one will be created ''' if len(y_values.shape) < 2: y_values.shape = (1, ) + y_values.shape if x_values.shape[0] != y_values.shape[1]: LOGGER.error('mismatched array lengths') return if camera is None: camera = pi3d.Camera(is_3d=False) if shader is None: shader = pi3d.Shader('mat_flat') # title ########## point_size = max(min(48, int(height * 0.1)), 24) self.text = pi3d.PointText(font, camera, max_chars=400, point_size=point_size) if title is not None: title = pi3d.TextBlock(x=xpos, y=ypos + height / 2 - point_size + 5, z=0.1, rot=0.0, char_count=len(title) + 2, spacing='F', text_format=title, space=0.05, justify=0.5) self.text.add_text_block(title) # axes ########### axex, axey = width * 0.4, height * 0.4 # implies 10% margin all round self.axes = pi3d.Lines( vertices=[[axex, -axey - line_width, 0], [-axex - line_width, -axey - line_width, 0], [-axex - line_width, axey, 0]], x=xpos, y=ypos, z=5.0, line_width=line_width) self.axes.set_shader(shader) # lines to represent data n = x_values.shape[-1] if xmin is None: xmin = x_values.min() if xmax is None: xmax = x_values.max() x_factor = (2.0 * axex) / (xmax - xmin) x_offset = xmin if ymin is None: ymin = y_values.min() if ymax is None: ymax = y_values.max() y_factor = (2.0 * axey) / (ymax - ymin) y_offset = ymin self.lines = [] for i in range(y_values.shape[0]): data = np.zeros((n, 3)) data[:, 0] = (x_values - x_offset) * x_factor - axex + xpos if len(y_values[i].shape) == 1: # i.e. normal line graph data[:, 1] = (y_values[i] - y_offset) * y_factor - axey + ypos strip = True else: # has to be pairs of values for separate line segments xx_vals = np.stack([data[:, 0], data[:, 0]], axis=1).flatten() # make x into pairs data = np.zeros((n * 2, 3)) data[:, 0] = xx_vals data[:, 1] = (y_values[i].flatten() - y_offset) * y_factor - axey + ypos strip = False data[:, 2] = 4.0 # z value line = pi3d.Lines(vertices=data, line_width=line_width, strip=strip) line.set_shader(shader) j = i + 1 rgb_val = (0.913 * j % 1.0, 0.132 * j % 1.0, 0.484 * j % 1.0) line.set_material(rgb_val) self.lines.append(line) # axis values point_size *= 0.3 # first add the max and min vals vals = [(-axex + xpos, -axey + ypos - point_size, '{:.3g}'.format(xmin), 0.0), (axex + xpos, -axey + ypos - point_size, '{:.3g}'.format(xmax), 0.0), (-axex + xpos - point_size, -axey + ypos, '{:.3g}'.format(ymin), 90.0), (-axex + xpos - point_size, axey + ypos, '{:.3g}'.format(ymax), 90.0)] data = [ ] # use this to hold vertex positions for grid lines (called ticks) for val in self.tick_pos(xmin, xmax): x = (val - x_offset) * x_factor - axex vals.append((x + xpos, -axey + ypos - point_size, '{:.3g}'.format(val), 0.0)) data.extend([[x, -axey, 0], [x, axey, 0]]) # NB points in pairs to use GL_LINES option with strip=False below. for val in self.tick_pos(ymin, ymax): y = (val - y_offset) * y_factor - axey vals.append((-axex + xpos - point_size, y + ypos, '{:.3g}'.format(val), 90.0)) data.extend([[-axex, y, 0], [axex, y, 0]]) for val in vals: self.text.add_text_block( pi3d.TextBlock(val[0], val[1], 4.0, val[3], 8, size=0.7, text_format=val[2], spacing='F', space=0.05, justify=0.5)) self.ticks = pi3d.Lines(vertices=data, x=xpos, y=ypos, z=5.0, line_width=line_width, material=(0.5, 0.5, 0.5), strip=False) self.ticks.set_shader(shader) # axes descritions if axes_desc is not None: self.text.add_text_block( pi3d.TextBlock(xpos, ypos - 1.15 * axey, 4.0, 0.0, len(axes_desc[0]) + 2, size=0.7, text_format=axes_desc[0], spacing='F', space=0.05, justify=0.5)) self.text.add_text_block( pi3d.TextBlock(xpos - 1.15 * axex, ypos, 4.0, 90.0, len(axes_desc[1]) + 2, size=0.7, text_format=axes_desc[1], spacing='F', space=0.05, justify=0.5)) # legend ########## if legend is not None: if not hasattr(legend, '__iter__'): # single string, make into list legend = [legend] for i, lgd in enumerate(legend): self.text.add_text_block( pi3d.TextBlock( axex + xpos, axey + ypos - (i + 1) * point_size * 2.0, 4.0, 0.0, len(lgd) + 2, size=0.8, text_format=lgd, spacing='F', space=0.05, justify=1.0, colour=tuple(self.lines[i].buf[0].unib[3:6]) + (1.0, ))) # scale factors for use in update() so add to self self.y_offset = y_offset self.y_factor = y_factor self.axey = axey self.ypos = ypos
#!/usr/bin/env python # -*- coding: utf-8 -*- import config import core.peripherals as peripherals import core.graphics as graphics import sys import os import pi3d sys.path.insert(1, os.path.join(sys.path[0], '..')) text5 = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=20, point_size=64) # slider5 Ammeter currents = pi3d.TextBlock(-350, 100, 0.1, 0.0, 15, data_obj=peripherals.eg_object, attr="relais1current", text_format="{:2.1f}A", size=0.99, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text5.add_text_block(currents) amperemeter = pi3d.ImageSprite(config.installpath + 'sprites/amperemeter.png', shader=graphics.SHADER, camera=graphics.CAMERA, w=400, h=400, x=0, y=0, z=2.0) ampereneedle = pi3d.Lines(camera=graphics.CAMERA, vertices=( (0, 0, 0), (0, 160, 0)), material=(1.0, 0.3, 0.0), line_width=5, x=0.0, y=-70.0, z=1.0) ampereneedle.set_shader(graphics.MATSH) def inloop(textchange=False, activity=False, offset=0): if offset != 0: offset = graphics.slider_change(amperemeter, offset)
def __init__(self, angle_fr=-140, angle_to=140, step=8, x=0, y=0, outer=250, inner=180, min_v=15, max_v=30, text_format="{:4.1f}°", set_field="set_temp", act_field="act_temp", shader=None, camera=None): self.angle_fr = angle_fr self.angle_to = ((angle_to - angle_fr) // step + 1) * step + angle_fr self.step = step self.outer = outer self.inner = inner self.mid = (outer + inner) / 2 self.min_v = min_v self.max_v = max_v self.x = x self.y = y self.set_field = set_field self.act_field = act_field self.text_format = text_format tick_verts = [] dial_verts = [] # first make tick vertices for x2 in range(self.angle_fr, self.angle_to, self.step): (s, c) = (sin(radians(x2)), cos(radians(x2)) ) # re-use for brevity below tick_verts.extend([(self.inner * s, self.inner * c, 0.1), (self.outer * s, self.outer * c, 0.1)]) dial_verts.append((self.mid * s, self.mid * c, 2.0)) tex = pi3d.Texture( resource_filename("shpi", "sprites/color_gradient.jpg")) self.ticks = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=tick_verts, strip=False, line_width=8) self.ticks.set_shader(graphics.MATSH) self.ticks.set_alpha(0.8) self.sensorticks = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=tick_verts, line_width=8, strip=False) self.sensorticks.set_shader(graphics.MATSH) self.bline = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=dial_verts, line_width=80) self.bline.set_textures([tex]) self.bline.set_alpha(0.8) self.bline.set_shader(graphics.SHADER) self.bline.set_material((0.5, 0.5, 0.5)) self.trian = pi3d.Triangle(camera=graphics.CAMERA, x=self.x, y=self.y, z=0.1, corners=((-15, self.inner - 20, 0), (0, self.inner + 5, 0), (15, self.inner - 20, 0))) self.trian.set_shader(graphics.MATSH) self.trian.set_material((0.3, 0.1, 0)) self.trian.set_alpha(1) self.dial = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=dial_verts, line_width=84) self.dial.set_alpha(0.2) self.dial.set_shader(graphics.MATSH) self.dial.set_material((0, 0, 0)) self.actval = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=23, point_size=100) self.val_block = pi3d.TextBlock(self.x, self.y + 10, 0.1, 0.0, 11, justify=0.6, text_format=text_format, size=0.99, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) self.actval.add_text_block(self.val_block) self.value = getattr(peripherals.eg_object, self.set_field) self.sensorvalue = getattr(peripherals.eg_object, self.act_field) self.set_block = pi3d.TextBlock(0, self.inner - 30, 0.1, 0, 11, text_format=self.text_format.format( self.value), size=0.35, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1), justify=0.6) self.actval.add_text_block(self.set_block) self.dot1 = pi3d.Disk(radius=130, sides=30, x=self.x, y=self.y, z=2, rx=90, camera=graphics.CAMERA) self.dot1.set_shader(graphics.MATSH) self.dot1.set_material((0, 0, 0)) self.dot1.set_alpha(0.4) self.dot2 = pi3d.Disk(radius=30, sides=20, x=self.x, y=self.y, z=0.1, rx=90, camera=graphics.CAMERA) self.dot2.set_shader(graphics.MATSH) self.dot2.set_material((1, 1, 1)) self.dot2_alpha = 1.0 self.degree = (self.angle_fr + (self.angle_to - self.angle_fr) * (self.value - self.min_v) / (self.max_v - self.min_v)) self.trian.rotateToZ(-self.degree + self.step) if self.sensorvalue < self.min_v: self.sensorvalue = self.min_v if self.sensorvalue > self.max_v: self.sensorvalue = self.max_v self.sensordegree = (self.angle_fr + (self.angle_to - self.angle_fr) * (self.sensorvalue - self.min_v) / (self.max_v - self.min_v)) self.x1 = self.mid * sin(radians(self.degree)) + self.x self.y1 = self.mid * cos(radians(self.degree)) + self.y self.changed = 0 self.dot2.position(self.x1, self.y1, 0.5) self.dot2_alpha = 1.0 self.set_block.set_position( x=(self.inner - 33) * sin(radians(self.degree - self.step)) + self.x, y=(self.inner - 33) * cos(radians(self.degree - self.step)) + self.y, rot=-self.degree + self.step)
x=0, y=-180) grapharea.set_shader(graphics.MATSH) grapharea.set_material((1.0, 1.0, 1.0)) grapharea.set_alpha(0.3) grapharea2 = pi3d.Sprite(camera=graphics.CAMERA, w=780, h=350, z=3.0, x=0, y=55) grapharea2.set_shader(graphics.MATSH) grapharea2.set_material((0, 0, 0)) grapharea2.set_alpha(0.7) text = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=850, point_size=128) error = False def init(): global seplines, degwind, weathericon, text, line, baroneedle, windneedle, linemin, linemax, acttemp, text, error try: owm = pyowm.OWM(API_key=config.owmkey, language=config.owmlanguage) place = owm.weather_at_place(config.owmcity) weather = place.get_weather() text.text_blocks = [] text._first_free_char = 0
QWIDTH = HWIDTH / 2 # quarter width CAMERA = pi3d.Camera(is_3d=False) font_colour = (255, 255, 255, 255) text_pos = QWIDTH working_directory = os.path.dirname(os.path.realpath(__file__)) font_path = os.path.abspath( os.path.join(working_directory, 'fonts', 'NotoSans-Regular.ttf')) # Create pointFont and the text manager to use it pointFont = pi3d.Font(font_path, font_colour, codepoints=list(range(32, 128))) text = pi3d.PointText(pointFont, CAMERA, max_chars=220, point_size=64) #Basic static text newtxt = pi3d.TextBlock(-100, -50, 0.1, 0.0, 14, text_format="Static string", size=0.99, spacing="F", space=0.05, colour=(0.0, 1.0, 0.0, 1.0)) text.add_text_block(newtxt) """The next three strings are formated with data from an object. When the object data changes and the text block is regenerated, the string is
def __init__(self, x=0, y=0, inner=100, outer=200, values=[], colors=[], full_range=None, concentric=False, start=0.0, end=None, sides=36, text_format="{:.1f}", camera=graphics.CAMERA, shader=graphics.MATSH): self.x = x self.y = y self.inner = inner self.outer = outer self.full_range = full_range self.concentric = concentric self.start = start if end is None: self.end = start + 360 else: self.end = end if type(text_format) in (list, tuple): self.text_format = text_format else: self.text_format = [text_format] * len(values) self.slices = [] if full_range is None: full_range = sum(values) self.n = len(values) # simplest Shape only 3 vertices. z -1 so not drawn self.empty = pi3d.Triangle(x=x, y=y, z=-1.0) self.text = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=(self.n * 26), point_size=64) tot = self.start step = (outer - inner) / self.n for i in range(self.n): end = (self.end - self.start) * values[i] / full_range if concentric: a_slice = Slice( camera=camera, inner=inner + i * step, outer=inner + (i + 1) * step, sides=sides, start=self.start, end=end, z=3.0 ) #z=3 to compensate for empty set to -1 and draw behind labels else: a_slice = Slice(camera=camera, inner=inner, outer=outer, start=tot, end=tot + end, z=3.0) tot += end buf = a_slice.buf[0].array_buffer # alias for brevity midv = len( buf ) // 2 # text half way round curve, miday between inner and outer text_x = (buf[midv, 0] + buf[midv + 1, 0]) / 2 + self.x text_y = (buf[midv, 1] + buf[midv + 1, 1]) / 2 + self.y slice_text = pi3d.TextBlock(text_x, text_y, 0.0, 0.0, 25, text_format=self.text_format[i].format( values[i]), size=0.5, spacing="C", space=0.6, justify=0.5) self.text.add_text_block(slice_text) a_slice.set_shader(shader) a_slice.set_material(colors[i]) self.slices.append(a_slice) self.empty.add_child(a_slice)
def init(): global seplines, degwind, weathericon, text, line, baroneedle, windneedle, linemin, linemax, acttemp text = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=700, point_size=128) owm = pyowm.OWM(API_key=config.owmkey, language=config.owmlanguage) place = owm.weather_at_place(config.owmcity) weather = place.get_weather() if config.owmlanguage == 'de': weekdays = [ 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag' ] else: weekdays = [ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ] if not os.path.exists('sprites/' + weather.get_weather_icon_name() + '.png'): import urllib.request urllib.request.urlretrieve( "http://openweathermap.org/img/wn/" + weather.get_weather_icon_name() + "@2x.png", "sprites/" + weather.get_weather_icon_name() + ".png") weathericon = pi3d.ImageSprite(config.installpath + 'sprites/' + weather.get_weather_icon_name() + '.png', shader=graphics.SHADER, camera=graphics.CAMERA, w=150, h=150, z=2, x=-220) city = pi3d.TextBlock(-390, 180, 0.1, 0.0, 150, text_format=place.get_location().get_name(), size=0.7, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(city) city = pi3d.TextBlock(-380, 80, 0.1, 0.0, 30, text_format=weather.get_detailed_status(), size=0.4, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(city) # acttemp = pi3d.TextBlock(-280, 0, 0.1, 0.0, 10, text_format= str(weather.get_temperature(unit='celsius')['temp']) + '°C' , size=0.5, spacing="F",space=0.05,colour=(1.0, 1.0, 1.0,1.0)) #text.add_text_block(acttemp) acttemp = pi3d.FixedString( config.installpath + 'fonts/opensans.ttf', str(weather.get_temperature(unit='celsius')['temp']) + '°C', font_size=42, shadow_radius=1, justify='L', color=(255, 255, 255, 255), camera=graphics.CAMERA, shader=graphics.SHADER, f_type='SMOOTH') acttemp.sprite.position(-210, -50, 1) sunriset = weather.get_sunrise_time( timeformat='date') + datetime.timedelta(hours=2) sunsett = weather.get_sunset_time(timeformat='date') + datetime.timedelta( hours=2) sunset = pi3d.TextBlock(50, 100, 0.1, 0.0, 20, text_format=chr(0xE041) + " %s:%02d" % (sunriset.hour, sunriset.minute) + ' ' + chr(0xE042) + " %s:%02d" % (sunsett.hour, sunsett.minute), size=0.3, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(sunset) barometer = pi3d.TextBlock(50, -50, 0.1, 0.0, 10, text_format=chr(0xE00B) + ' ' + str(weather.get_pressure()['press']) + ' hPa', size=0.3, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(barometer) baroneedle = pi3d.Triangle(camera=graphics.CAMERA, corners=((-2, 0, 0), (0, 7, 0), (2, 0, 0)), x=barometer.x + 16, y=barometer.y - 6, z=0.1) baroneedle.set_shader(graphics.MATSH) normalizedpressure = (weather.get_pressure()['press'] - 950) if normalizedpressure < 0: normalizedpressure = 0 if normalizedpressure > 100: normalizedpressure = 100 green = 0.02 * (normalizedpressure) if green > 1: green = 1 red = 0.02 * (100 - normalizedpressure) if red > 1: red = 1 barometer.colouring.set_colour([red, green, 0, 1.0]) baroneedle.set_material([red, green, 0]) baroneedle.rotateToZ(100 - (normalizedpressure * 2)) humidity = pi3d.TextBlock(50, 0, 0.1, 0.0, 10, text_format=chr(0xE003) + ' ' + str(weather.get_humidity()) + '%', size=0.3, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(humidity) if 'speed' in weather.get_wind(): wind = pi3d.TextBlock(50, 50, 0.1, 0.0, 10, text_format=chr(0xE040) + ' ' + str(weather.get_wind()['speed']) + 'm/s', size=0.3, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(wind) if 'deg' in weather.get_wind(): degwind = True windneedle = pi3d.Triangle(camera=graphics.CAMERA, corners=((-3, 0, 0), (0, 15, 0), (3, 0, 0)), x=wind.x + 180, y=wind.y, z=0.1) windneedle.set_shader(graphics.MATSH) windneedle.set_material([1, 1, 1]) windneedle.rotateToZ(weather.get_wind()['deg']) else: degwind = False fc = owm.three_hours_forecast(config.owmcity) f = fc.get_forecast() step = 780 / (len(f)) actualy = -400 + step temp_max = [] temp_min = [] temp = [] seplines = [] icons = [] maxdaytemp = -100 mindaytemp = 100 for weather in f: if not os.path.exists('sprites/' + weather.get_weather_icon_name() + '.png'): import urllib.request urllib.request.urlretrieve( "http://openweathermap.org/img/wn/" + weather.get_weather_icon_name() + "@2x.png", "sprites/" + weather.get_weather_icon_name() + ".png") icons.append( pi3d.ImageSprite('sprites/' + weather.get_weather_icon_name() + '.png', shader=graphics.SHADER, camera=graphics.CAMERA, w=20, h=20, z=1, x=actualy, y=-220)) if weather.get_reference_time('iso')[11:16] == '00:00': line = pi3d.Lines(vertices=[[actualy, -50, 2], [actualy, 50, 2]], line_width=1, y=-180, strip=True) line.set_shader(graphics.MATSH) line.set_material((0, 0, 0)) line.set_alpha(0.9) seplines.append(line) #if weather.get_reference_time('iso')[11:16] == '12:00': day = weather.get_reference_time(timeformat='date').weekday() if actualy < 300: city = pi3d.TextBlock(actualy + 65, -100, 0.1, 0.0, 30, text_format=weekdays[day], justify=0.5, size=0.23, spacing="F", space=0.05, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(city) if actualy > -300: city = pi3d.TextBlock(actualy - 6 * step, -150, 0.1, 0.0, 30, text_format=str(round(maxdaytemp, 1)) + '°C', size=0.25, spacing="F", space=0.05, colour=(1.0, 0.0, 0.0, 1.0)) text.add_text_block(city) city = pi3d.TextBlock(actualy - 6 * step, -210, 0.1, 0.0, 30, text_format=str(round(mindaytemp, 1)) + '°C', size=0.25, spacing="F", space=0.05, colour=(0.0, 0.0, 1.0, 1.0)) text.add_text_block(city) maxdaytemp = -100 mindaytemp = 100 if '3h' in weather.get_snow(): line = pi3d.Lines( vertices=[[actualy, -50, 2], [actualy, (-50 + weather.get_snow()['3h'] * 30), 2]], line_width=3, y=-180, strip=True) line.set_shader(graphics.MATSH) line.set_material((0.5, 0.5, 1)) line.set_alpha(1) seplines.append(line) if '3h' in weather.get_rain(): line = pi3d.Lines( vertices=[[actualy, -50, 2], [actualy, (-50 + weather.get_rain()['3h'] * 30), 2]], line_width=3, y=-180, strip=True) line.set_shader(graphics.MATSH) line.set_material((0, 0, 1)) line.set_alpha(1) seplines.append(line) temperatures = weather.get_temperature(unit='celsius') if temperatures['temp_max'] > maxdaytemp: maxdaytemp = temperatures['temp_max'] if temperatures['temp_min'] < mindaytemp: mindaytemp = temperatures['temp_min'] temp_max.append([actualy, temperatures['temp_max'] * 3, 2]) temp_min.append([actualy, temperatures['temp_min'] * 3, 2]) temp.append([actualy, temperatures['temp'] * 3, 2]) actualy += step lastvalue = 0 line = pi3d.Lines(vertices=temp, line_width=2, y=-220, strip=True) line.set_shader(graphics.MATSH) line.set_material((0, 0, 0)) line.set_alpha(0.9) linemin = pi3d.Lines(vertices=temp_min, line_width=1, y=-220, strip=True) linemin.set_shader(graphics.MATSH) linemin.set_material((0, 0, 1)) linemin.set_alpha(0.9) linemax = pi3d.Lines(vertices=temp_max, line_width=1, y=-220, strip=True) linemax.set_shader(graphics.MATSH) linemax.set_material((1, 0, 0)) linemax.set_alpha(0.9)
dir = '' fname = '' date = '' status = '' text_attr = TextAttr() font = pi3d.Font(FONT_FILE, FONT_COLOUR, codepoints=list(range(32, 128)), shadow_radius=4.0, shadow=(0, 0, 0, 128)) colourGradient = pi3d.TextBlockColourGradient((1.0, 0.0, 0.0, 1.0), (0.0, 1.0, 0.0, 1.0)) file_pt = pi3d.PointText(font, CAMERA, max_chars=216, point_size=80) dir_tb = pi3d.TextBlock(x=DISPLAY.width * -0.5 + 50, y=DISPLAY.height * -0.5 + 100, z=0.1, rot=0.0, char_count=100, text_format='{:100}', data_obj=text_attr, attr="dir", size=0.5, spacing="F", space=0.02, colour=colourGradient) file_pt.add_text_block(dir_tb) file_tb = pi3d.TextBlock(x=DISPLAY.width * -0.5 + 50,
def __init__(self, width=600, step=20, x=-300, y=0, thickness=50, min_t=1, max_t=31): self.width = width self.step = step self.thickness = thickness self.min_t = min_t self.max_t = max_t self.x = x self.y = y self.value = max_t tick_verts = [] dial_verts = [] bline_verts = [] # first make tick vertices for x2 in range(0, self.width, self.step): tick_verts.extend([(x2, -self.thickness / 2, 0.2), (x2, self.thickness / 2, 0.2)]) bline_verts.append((x2, 0, 0.5)) for x2 in range(self.x - 9, self.x + self.width + 3, self.step): dial_verts.append((x2, 0, 0.5)) tex = pi3d.Texture( resource_filename("shpi", "sprites/color_gradient.jpg")) self.ticks = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=tick_verts, strip=False, line_width=15) self.ticks.set_shader(graphics.MATSH) self.ticks.set_alpha(0.6) self.bline = pi3d.PolygonLines(camera=graphics.CAMERA, x=self.x, y=self.y, vertices=bline_verts, line_width=self.thickness) self.bline.set_textures([tex]) self.bline.set_alpha(0.5) self.bline.set_shader(graphics.SHADER) self.bline.set_material((0.5, 0.5, 0.5)) self.dial = pi3d.PolygonLines(camera=graphics.CAMERA, x=0, y=self.y, vertices=dial_verts, line_width=self.thickness + 6) self.dial.set_alpha(0.4) self.dial.set_shader(graphics.MATSH) self.dial.set_material((0, 0, 0)) self.actval = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=8, point_size=100) self.temp_set = pi3d.TextBlock(self.x, self.y + 50, 0.1, 0.0, 2, text_format="00", size=0.6, spacing="F", space=0.02, colour=(0.0, 0.0, 0.0, 1), justify=1) self.actval.add_text_block(self.temp_set) self.dot2 = pi3d.Disk(radius=int(self.thickness / 2) + 3, sides=30, x=self.x, y=self.y, z=0.2, rx=90, camera=graphics.CAMERA) self.dot2.set_shader(graphics.MATSH) self.dot2.set_material((1, 1, 1)) self.dot2.set_alpha(0.8) self.valuex = 0 self.changed = 0
def __init__(self, config): # noinspection PyBroadException try: locale.setlocale(locale.LC_TIME, config.local) except Exception as e: log.warning("error trying to set local to {}".format(config.local), e) self._display = pi3d.Display.create( x=config.display_x, y=config.display_y, w=config.display_w, h=config.display_h, frames_per_second=config.fps, display_config=pi3d.DISPLAY_CONFIG_HIDE_CURSOR, background=config.background, ) self._camera = pi3d.Camera(is_3d=False) shader = pi3d.Shader(config.shader) self._slide = pi3d.Sprite( camera=self._camera, w=self._display.width, h=self._display.height, z=5.0 ) self._slide.set_shader(shader) self._slide.unif[47] = config.edge_alpha self._slide.unif[54] = config.blend_type self._slide.unif[55] = 1.0 # brightness used by shader [18][1] if config.keyboard: self.keyboard = pi3d.Keyboard() grid_size = math.ceil(len(config.codepoints) ** 0.5) font = pi3d.Font( config.font_file, codepoints=config.codepoints, grid_size=grid_size ) self._text = pi3d.PointText( font, self._camera, max_chars=200, point_size=config.show_text_sz ) self._textblock = pi3d.TextBlock( x=0, y=-self._display.height // 2 + (config.show_text_sz // 2) + 20, z=0.1, rot=0.0, char_count=199, text_format="{}".format(" "), size=0.99, spacing="F", justify=0.5, space=0.02, colour=(1.0, 1.0, 1.0, 1.0), ) self._text.add_text_block(self._textblock) bkg_ht = self._display.height // 4 text_bkg_array = np.zeros((bkg_ht, 1, 4), dtype=np.uint8) text_bkg_array[:, :, 3] = np.linspace(0, 170, bkg_ht).reshape(-1, 1) text_bkg_tex = pi3d.Texture(text_bkg_array, blend=True, free_after_load=True) self._text_bkg = pi3d.Plane( w=self._display.width, h=bkg_ht, y=-self._display.height // 2 + bkg_ht // 2, z=4.0, ) back_shader = pi3d.Shader("uv_flat") self._text_bkg.set_draw_details(back_shader, [text_bkg_tex]) self._foreground_slide = None self._background_slide = None
def __init__(self, angle_fr=-135, angle_to=135, step=5, outer=240, inner=200, min_t=15, max_t=35, shader=None, camera=None): self.angle_fr = angle_fr self.angle_to = angle_to self.step = step self.outer = outer self.inner = inner self.mid = (outer + inner) / 2 self.min_t = min_t self.max_t = max_t gpio.setmode(gpio.BCM) gpio.setwarnings(False) gpio.setup(26, gpio.IN, pull_up_down=gpio.PUD_DOWN) self.bus = i2c.I2C(2) try: self.bus.read(1, 0x5c) self.bus.write([0x6e, 0b00001110], 0x5c) self.bus.write([0x70, 0b00000000], 0x5c) except: print('Error: no touchscreen found') tick_verts = [] dial_verts = [] # first make tick vertices for x in range(self.angle_fr, self.angle_to, self.step): (s, c) = (sin(radians(x)), cos(radians(x)) ) # re-use for brevity below tick_verts.extend([(self.inner * s, self.inner * c, 0.1), (self.outer * s, self.outer * c, 0.1)]) dial_verts.append((self.mid * s, self.mid * c, 2.0)) if shader is None: shader = pi3d.Shader('mat_flat') if camera is None: camera = pi3d.Camera(is_3d=False) uv_shader = pi3d.Shader('uv_flat') tex = pi3d.Texture('color_gradient.jpg') self.ticks = pi3d.PolygonLines(camera=camera, vertices=tick_verts, strip=False, line_width=5) self.ticks.set_shader(shader) self.ticks.set_alpha(0.8) self.sensorticks = pi3d.PolygonLines(camera=camera, vertices=tick_verts, line_width=5, strip=False) self.sensorticks.set_shader(shader) self.bline = pi3d.PolygonLines(camera=camera, vertices=dial_verts, line_width=40) self.bline.set_textures([tex]) self.bline.set_alpha(0.8) self.bline.set_shader(uv_shader) self.bline.set_material((0.5, 0.5, 0.5)) self.dial = pi3d.PolygonLines(camera=camera, vertices=dial_verts, line_width=8) self.dial.set_alpha(0.2) self.dial.set_shader(shader) font = pi3d.Font('opensans.ttf', codepoints='0123456789.-°', grid_size=5) self.actval = pi3d.PointText(font, camera, max_chars=10, point_size=100) self.temp_block = pi3d.TextBlock(0, 0, 0.1, 0.0, 6, justify=0.5, text_format="0°", size=0.79, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) self.actval.add_text_block(self.temp_block) self.dot2 = pi3d.Disk(radius=20, sides=20, z=0.1, rx=90, camera=camera) self.dot2.set_shader(shader) self.dot2.set_material((1, 1, 1)) self.dot2_alpha = 1.0 self.value = 25.0 self.sensorvalue = 18.0 degree = (self.angle_fr + (self.angle_to - self.angle_fr) * (self.value - self.min_t) / (self.max_t - self.min_t)) self.x1 = self.mid * sin(radians(degree)) self.y1 = self.mid * cos(radians(degree))
kbd = pi3d.Keyboard() # images in iFiles list nexttm = 0.0 iFiles, nFi = get_files(date_from, date_to) next_pic_num = 0 sfg = None # slide for background sbg = None # slide for foreground if nFi == 0: print('No files selected!') exit() # PointText and TextBlock. If SHOW_NAMES is False then this is just used for no images message font = pi3d.Font(FONT_FILE, codepoints=CODEPOINTS, grid_size=7, shadow_radius=4.0, shadow=(0,0,0,128)) text = pi3d.PointText(font, CAMERA, max_chars=200, point_size=50) textblock = pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 50, y=-DISPLAY.height * 0.4, z=0.1, rot=0.0, char_count=199, text_format="{}".format(" "), size=0.99, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(textblock) num_run_through = 0 while DISPLAY.loop_running(): tm = time.time() if nFi > 0: if (tm > nexttm and not paused) or (tm - nexttm) >= 86400.0: # this must run first iteration of loop nexttm = tm + time_delay a = 0.0 # alpha - proportion front image to back sbg = sfg sfg = None
import core.peripherals as peripherals import core.graphics as graphics import config import pi3d import sys import os sys.path.insert(1, os.path.join(sys.path[0], '..')) try: unichr except NameError: unichr = chr text2 = pi3d.PointText(graphics.pointFontbig, graphics.CAMERA, max_chars=35, point_size=256) # slider2 Time & shutter if config.shutterup or config.shutterdown: uhrzeit_block = pi3d.TextBlock(-70, 100, 0.1, 0.0, 15, justify=0.5, data_obj=peripherals.eg_object, attr="uhrzeit", text_format="{:s}", size=0.99, spacing="F", space=0.05,
def init(): global text6, actualy, displayheight if config.icallink.startswith('http'): icalfile = requests.get(config.icallink).text else: icalfile = open(config.installpath + config.icallink, 'r') gcal = Calendar.from_ical(icalfile.read()) components = gcal.walk() now2 = datetime.now() components = filter(lambda c: c.name == 'VEVENT', components) components = filter(lambda c: c.get('dtstart').dt.replace( tzinfo=None) - now2 > timedelta(0), components) # filter out past events components = sorted( components, key=lambda c: c.get('dtstart').dt.replace(tzinfo=None) - now2, reverse=False) # order dates soonist to now to farthest text6 = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=1000, point_size=128) count = 0 mystring = '' actualy = -100 for e in components: if count < 5: start = arrow.get(e.get('dtstart').dt) size = 0.79 titles = pi3d.TextBlock(-390, ((displayheight / 2) + actualy - (graphics.pointFont.height * size * 0.5)), 0.1, 0.0, 30, text_format=start.humanize().title(), size=size, spacing="F", space=0.02, colour=(1, 0, 0, 1)) text6.add_text_block(titles) actualy -= titles.size * graphics.pointFont.height size = 0.29 date = pi3d.TextBlock( -380, ((displayheight / 2) + actualy - (graphics.pointFont.height * size * 0.5)), 0.1, 0.0, 12, text_format='(' + start.format('DD.MM.YYYY') + ')', size=size, spacing="F", space=0.02, colour=(1, 1, 1, 1)) text6.add_text_block(date) actualy -= date.size * graphics.pointFont.height size = 0.4 width = 0 subtext = '' actualword = '' g_scale = float(text6.point_size) / graphics.pointFont.height for c in e.get('summary'): width += graphics.pointFont.glyph_table[c][0] * g_scale * size actualword += c if c in (' ', '-', ',', '.', '+', ':'): subtext += actualword actualword = '' if width > 730: event = pi3d.TextBlock( -350, (displayheight / 2) + actualy - (graphics.pointFont.height * size * 0.5), 0.1, 0.0, 40, text_format=subtext, size=size, spacing="F", space=0.02, colour=(1, 1, 1, 1)) text6.add_text_block(event) subtext = '' width = 0 actualy -= event.size * graphics.pointFont.height if (subtext != '') or (actualword != ''): event = pi3d.TextBlock( -350, (displayheight / 2) + actualy - (graphics.pointFont.height * size * 0.5), 0.1, 0.0, 40, text_format=subtext + actualword, size=size, spacing="F", space=0.02, colour=(1, 1, 1, 1)) text6.add_text_block(event) actualy -= event.size * graphics.pointFont.height actualy -= 20 count += 1 else: break icalfile.close()
kbd = pi3d.Keyboard() # images in iFiles list nexttm = 0.0 iFiles, nFi = get_files(date_from, date_to) next_pic_num = 0 sfg = None # slide for background sbg = None # slide for foreground # PointText and TextBlock. If SHOW_TEXT_TM <= 0 then this is just used for no images message grid_size = math.ceil(len(config.CODEPOINTS)**0.5) font = pi3d.Font(config.FONT_FILE, codepoints=config.CODEPOINTS, grid_size=grid_size) text = pi3d.PointText(font, CAMERA, max_chars=200, point_size=config.SHOW_TEXT_SZ) textblock = pi3d.TextBlock(x=0, y=-DISPLAY.height // 2 + (config.SHOW_TEXT_SZ // 2) + 20, z=0.1, rot=0.0, char_count=199, text_format="{}".format(" "), size=0.99, spacing="F", justify=0.5, space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(textblock) """
import pi3d import sys, os sys.path.insert(1, os.path.join(sys.path[0], '..')) import urllib.request import config import core.graphics as graphics import core.peripherals as peripherals import core.mqttclient as mqttclient import json text = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=35, point_size=128) text2 = pi3d.PointText( graphics.pointFontbig, graphics.CAMERA, max_chars=35, point_size=256) #also big font possible, higher resolution # look for graphics in core/graphics.py 0xE00F -> light, 0xE001 -> circle httpbutton = pi3d.TextBlock(0, 0, 0.1, 0.0, 1, text_format=chr(0xE00F), size=0.99, spacing="C",
from .. import config # TODO need this import? from ..core import peripherals from ..core import graphics from ..core import mqttclient try: import urllib.request as urlopen except: from urllib2 import urlopen try: unichr except NameError: unichr = chr text = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=35, point_size=128) # also big font possible, higher resolution text2 = pi3d.PointText(graphics.pointFontbig, graphics.CAMERA, max_chars=35, point_size=256) # look for graphics in core/graphics.py 0xE00F -> light, 0xE001 -> circle httpbutton = pi3d.TextBlock(0, 0, 0.1, 0.0, 1, text_format=unichr( 0xE00F), size=0.99, spacing="C", space=0.6, colour=(1, 1, 1, 1)) circle = pi3d.TextBlock(-5, 15, 0.1, 0.0, 1, text_format=unichr(0xE001), size=0.99, spacing="C", space=0.6, colour=(1, 1, 1, 1)) text.add_text_block(httpbutton) text2.add_text_block(circle) httpbutton.status = 'unknown' # on init status is unknown
#!/usr/bin/env python # -*- coding: utf-8 -*- import core.peripherals as peripherals import core.graphics as graphics import config import sys import os import pi3d sys.path.insert(1, os.path.join(sys.path[0], '..')) text3 = pi3d.PointText(graphics.pointFont, graphics.CAMERA, max_chars=820, point_size=64) # slider3 Inputs def add_to_text3(x, y, n_ch, text_format, attr=None, space=0.6, colour=(1.0, 1.0, 1.0, 1.0)): '''convenience function to avoid too much repitition''' newtxt = pi3d.TextBlock(x, y, 0.1, 0.0, n_ch,
def start_picframe(): global date_from, date_to, quit, paused, nexttm, next_pic_num, iFiles, nFi, monitor_status, pcache, w_show_now if cfg['KENBURNS']: kb_up = True cfg['FIT'] = False cfg['BLUR_EDGES'] = False if cfg['BLUR_ZOOM'] < 1.0: cfg['BLUR_ZOOM'] = 1.0 sfg = None # slide for background sbg = None # slide for foreground delta_alpha = 1.0 / (cfg['FPS'] * cfg['FADE_TIME']) # delta alpha # Initialize pi3d system DISPLAY = pi3d.Display.create(x=0, y=0, frames_per_second=cfg['FPS'], display_config=pi3d.DISPLAY_CONFIG_HIDE_CURSOR, background=cfg['BACKGROUND']) CAMERA = pi3d.Camera(is_3d=False) shader = pi3d.Shader(cfg['SHADER']) slide = pi3d.Sprite(camera=CAMERA, w=DISPLAY.width, h=DISPLAY.height, z=5.0) slide.set_shader(shader) slide.unif[47] = cfg['EDGE_ALPHA'] slide.unif[54] = cfg['BLEND_TYPE'] if cfg['KEYBOARD']: kbd = pi3d.Keyboard() # PointText and TextBlock. If INFO_TXT_TIME <= 0 then this is just used for no images message grid_size = math.ceil(len(cfg['CODEPOINTS']) ** 0.5) font = pi3d.Font(cfg['FONT_FILE'], codepoints=cfg['CODEPOINTS'], grid_size=grid_size, shadow_radius=5.0, shadow=(0,0,0,128)) text = pi3d.PointText(font, CAMERA, max_chars=1000, point_size=cfg['TEXT_POINT_SIZE']) textlines = [] textlines.append( pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 50, y=DISPLAY.height * 0.45, text_format=" ", z=0.1, rot=0.0, char_count=100, size=0.8, spacing="F", space=0.0, colour=(1.0, 1.0, 1.0, 1.0)) ) textlines.append( pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 50, y=DISPLAY.height * 0.45 - 40, text_format=" ", z=0.1, rot=0.0, char_count=100, size=0.8, spacing="F", space=0.0, colour=(1.0, 1.0, 1.0, 1.0)) ) textlines.append( pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 50, y=-DISPLAY.height * 0.4, text_format=" ", z=0.1, rot=0.0, char_count=100, size=0.99, spacing="F", space=0.0, colour=(1.0, 1.0, 1.0, 1.0)) ) textlines.append( pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 50, y=-DISPLAY.height * 0.4 - 50, text_format=" ", z=0.1, rot=0.0, char_count=100, size=0.99, spacing="F", space=0.0, colour=(1.0, 1.0, 1.0, 1.0)) ) for item in textlines: text.add_text_block(item) # prepare to display weather info weather_interstitial = 'OFF' next_weather_tm = 0.0 weatherinfo = pi3d.PointText(font, CAMERA, max_chars=2000, point_size=cfg['W_POINT_SIZE']) weatherobj = weatherscreen.weather_obj_create(DISPLAY.width, DISPLAY.height) for _, obj in weatherobj['current'].items(): weatherinfo.add_text_block( obj ) for item in weatherobj['forecast']: for key, obj in item.items(): if key != 'icon': weatherinfo.add_text_block( obj ) weatherscreen.weather_set_alpha(weatherobj=weatherobj, alpha=0) next_check_tm = time.time() + cfg['CHECK_DIR_TM'] # check for new files or directory in image dir every n seconds next_monitor_check_tm = 0.0 num_run_through = 0 # here comes the main loop while DISPLAY.loop_running(): tm = time.time() if (tm > nexttm and not paused) or (tm - nexttm) >= 86400.0: if nFi > 0: nexttm = tm + cfg['TIME_DELAY'] sbg = sfg sfg = None if (w_show_now or (cfg['W_SKIP_CNT'] > 0 and next_pic_num > 0 and (next_pic_num % cfg['W_SKIP_CNT'] == 0))) and weather_interstitial == 'OFF': # show weather interstitial weather_interstitial = 'ON' sfg = tex_load(cfg['W_BACK_IMG'], 1, (DISPLAY.width, DISPLAY.height)) if w_show_now: w_show_now = False for item in textlines: item.colouring.set_colour(alpha=0) else: # continue with next picture if weather_interstitial == 'ON': weather_interstitial = 'FADE' start_pic_num = next_pic_num while sfg is None: # keep going through until a usable picture is found pic_num = next_pic_num sfg = tex_load(pic_num, iFiles, (DISPLAY.width, DISPLAY.height)) next_pic_num += 1 if next_pic_num >= nFi: num_run_through += 1 next_pic_num = 0 if next_pic_num == start_pic_num: nFi = 0 break # set description if cfg['INFO_TXT_TIME'] > 0.0: set_text_overlay(iFiles, pic_num, textlines) else: # could have a NO IMAGES selected and being drawn for item in textlines: item.colouring.set_colour(alpha=0.0) mqtt_publish_status( status="running", pic_num=pic_num ) if sfg is None: sfg = tex_load(cfg['NO_FILES_IMG'], 1, (DISPLAY.width, DISPLAY.height)) sbg = sfg mqtt_publish_status( status="no pictures found" ) a = 0.0 # alpha - proportion front image to back name_tm = tm + cfg['INFO_TXT_TIME'] if sbg is None: # first time through sbg = sfg slide.set_textures([sfg, sbg]) slide.unif[45:47] = slide.unif[42:44] # transfer front width and height factors to back slide.unif[51:53] = slide.unif[48:50] # transfer front width and height offsets wh_rat = (DISPLAY.width * sfg.iy) / (DISPLAY.height * sfg.ix) if (wh_rat > 1.0 and cfg['FIT']) or (wh_rat <= 1.0 and not cfg['FIT']): sz1, sz2, os1, os2 = 42, 43, 48, 49 else: sz1, sz2, os1, os2 = 43, 42, 49, 48 wh_rat = 1.0 / wh_rat slide.unif[sz1] = wh_rat slide.unif[sz2] = 1.0 slide.unif[os1] = (wh_rat - 1.0) * 0.5 slide.unif[os2] = 0.0 if cfg['KENBURNS']: xstep, ystep = (slide.unif[i] * 2.0 / cfg['TIME_DELAY'] for i in (48, 49)) slide.unif[48] = 0.0 slide.unif[49] = 0.0 kb_up = not kb_up if cfg['KENBURNS']: t_factor = nexttm - tm if kb_up: t_factor = cfg['TIME_DELAY'] - t_factor slide.unif[48] = xstep * t_factor slide.unif[49] = ystep * t_factor transition_happening = False if monitor_status.startswith("ON"): if a < 1.0: # image transition is happening transition_happening = True a += delta_alpha if a > 1.0: a = 1.0 slide.unif[44] = a * a * (3.0 - 2.0 * a) if weather_interstitial == 'ON': # fade in weather weatherscreen.weather_set_alpha(weatherobj=weatherobj, alpha=a) else: # fade in picture -> fade in text for item in textlines: item.colouring.set_colour(alpha=a) if weather_interstitial == 'FADE': # fade out weather weatherscreen.weather_set_alpha(weatherobj=weatherobj, alpha=1-a) if a==1: weather_interstitial = 'OFF' if nFi <= 0: textlines[0].set_text("NO IMAGES SELECTED") textlines[0].colouring.set_colour(alpha=1.0) next_check_tm = tm + 10.0 text.regen() elif tm > name_tm and tm < name_tm + 2.0 and weather_interstitial != 'ON': # fade out text alpha = 1- (tm - name_tm)/2.0 for item in textlines: item.colouring.set_colour(alpha=alpha) transition_happening = True text.regen() slide.draw() text.draw() if weather_interstitial != 'OFF': weatherinfo.regen() weatherinfo.draw() for item in weatherobj['forecast']: item['icon'].draw() for _, obj in weatherobj['static'].items(): obj.draw() else: # monitor OFF -> minimize system activity to reduce power consumption time.sleep(10) if not transition_happening: # no transition effect safe to reshuffle etc if tm > next_monitor_check_tm: # Check if it's time to switch monitor status scheduled_status = check_monitor_status(tm) if monitor_status != scheduled_status and not monitor_status.endswith("-MANUAL"): switch_HDMI(scheduled_status) paused = True if scheduled_status.startswith("OFF") else False monitor_status = scheduled_status mqtt_publish_status( fields="monitor_status" ) next_monitor_check_tm = tm + 60 # check every minute if monitor_status.startswith("ON"): if tm > next_check_tm: # time to check picture directory if pcache.refresh_cache() or (cfg['SHUFFLE'] and num_run_through >= cfg['RESHUFFLE_NUM']): # refresh file list required if cfg['RECENT_DAYS'] > 0 and not cfg['DATE_FROM']: # reset data_from to reflect that time is proceeding date_from = datetime.datetime.now() - datetime.timedelta(cfg['RECENT_DAYS']) date_from = (date_from.year, date_from.month, date_from.day) iFiles, nFi = get_files(date_from, date_to) num_run_through = 0 next_pic_num = 0 next_check_tm = tm + cfg['CHECK_DIR_TM'] # next check if tm > next_weather_tm: # refresh weather info weatherscreen.weather_refresh( weatherobj ) next_weather_tm = tm + cfg['W_REFRESH_DELAY'] # next check if cfg['KEYBOARD']: k = kbd.read() if k != -1: nexttm = time.time() if k==27: #ESC break if k==ord(' '): paused = not paused if k==ord('b'): # go back a picture next_pic_num -= 2 if next_pic_num < -1: next_pic_num = -1 if quit or show_camera: # set by MQTT break if cfg['KEYBOARD']: kbd.close() DISPLAY.destroy()
def main( startdir, # Root folder for images, with recursive search config_file, # File with list of file names (for fast restart) interval, # Seconds between images shuffle, # True or False geonamesuser, # User name for GeoNames server www.geonames.org check_dirs # Interval between checking folders in seconds ) : global backup_dir,paused,geoloc,last_file_change,kb_up,FIT,BLUR_EDGES # backup_dir = os.path.abspath(os.path.join(startdir,config.BKUP_DIR)) backup_dir = config.BKUP_DIR print(startdir) #print(config.BKUP_DIR) #print(backup_dir) if config.BUTTONS: pause_button = Button(8, hold_time=5) back_button = Button(9, hold_time=5) forward_button = Button(4,hold_time=5) pause_button.when_pressed = handle_press back_button.when_pressed = handle_press pause_button.when_held=handle_hold back_button.when_held=handle_hold forward_button.when_pressed=handle_press forward_button.when_held=handle_hold rotate_button = Button(5, hold_time=5) rotate_button.when_pressed= handle_press rotate_button.when_held=handle_hold paused=False next_check_tm=time.time()+check_dirs time_dot=True ############################################## # Create GeoNames locator object www.geonames.org geoloc=None try: geoloc=GeoNames(username=geonamesuser) except: print("Geographic information server not available") print("Setting up display") DISPLAY = pi3d.Display.create(x=0, y=0, frames_per_second=FPS,display_config=pi3d.DISPLAY_CONFIG_HIDE_CURSOR, background=BACKGROUND) CAMERA = pi3d.Camera(is_3d=False) print(DISPLAY.opengl.gl_id) shader = pi3d.Shader(config.PI3DDEMO + "/shaders/blend_new") #shader = pi3d.Shader("/home/patrick/python/pi3d_demos/shaders/blend_new") slide = pi3d.Sprite(camera=CAMERA, w=DISPLAY.width, h=DISPLAY.height, z=5.0) slide.set_shader(shader) slide.unif[47] = config.EDGE_ALPHA if KEYBOARD: kbd = pi3d.Keyboard() # images in iFiles list nexttm = 0.0 iFiles, nFi = get_files(startdir,config_file,shuffle) next_pic_num = 0 sfg = None # slide for foreground sbg = None # slide for background if nFi == 0: print('No files selected!') exit() # PointText and TextBlock. #font = pi3d.Font(FONT_FILE, codepoints=CODEPOINTS, grid_size=7, shadow_radius=4.0,shadow=(128,128,128,12)) grid_size = math.ceil(len(config.CODEPOINTS) ** 0.5) font = pi3d.Font(config.FONT_FILE, codepoints=config.CODEPOINTS, grid_size=grid_size, shadow_radius=4.0,shadow=(0,0,0,128)) text = pi3d.PointText(font, CAMERA, max_chars=200, point_size=50) text2 = pi3d.PointText(font, CAMERA, max_chars=8, point_size=50) #text = pi3d.PointText(font, CAMERA, max_chars=200, point_size=50) textblock = pi3d.TextBlock(x=-DISPLAY.width * 0.5 + 20, y=-DISPLAY.height * 0.4, z=0.1, rot=0.0, char_count=199, text_format="{}".format(" "), size=0.65, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) text.add_text_block(textblock) timeblock = pi3d.TextBlock(x=DISPLAY.width*0.5 - 150, y=DISPLAY.height * 0.5 - 50, z=0.1, rot=0.0, char_count=6, text_format="{}".format(" "), size=0.65, spacing="F", space=0.02, colour=(1.0, 1.0, 1.0, 1.0)) text2.add_text_block(timeblock) #Retrieve last image number to restart the slideshow from config.num file #Retrieve next directory check time cacheddata=(0,0,last_file_change,next_check_tm) try: with open(config_file+".num",'r') as f: cacheddata=json.load(f) num_run_through=cacheddata[0] next_pic_num=cacheddata[1] last_file_change=cacheddata[2] next_check_tm=cacheddata[3] except: num_run_through=0 next_pic_num=0 if (next_check_tm < time.time()) : #if stored check time is in the past, make it "now" next_check_tm = time.time() print("Start time ",time.strftime(config.TIME_FORMAT,time.localtime())) print("Next Check time ",time.strftime(config.TIME_FORMAT,time.localtime(next_check_tm))) print("Starting with round number ",num_run_through) print("Starting with picture number ",next_pic_num) tm=time.time() pic_num=next_pic_num # Main loop while DISPLAY.loop_running(): previous = tm # record previous time value, used to make cursor blink tm = time.time() if (time.localtime(previous).tm_sec < time.localtime(tm).tm_sec) : #blink dot time_dot = not(time_dot) #check if there are file to display if nFi > 0: # If needed, display new photo if (tm > nexttm and not paused) or (tm - nexttm) >= 86400.0: # this must run first iteration of loop print("tm es ",tm," nexttm es ", nexttm, " la resta ", tm-nexttm) nexttm = tm + interval a = 0.0 # alpha - proportion front image to back sbg = sfg sfg = None while sfg is None: # keep going through until a usable picture is found TODO break out how? # Calculate next picture index to be shown pic_num = next_pic_num next_pic_num += 1 if next_pic_num >= nFi: num_run_through += 1 next_pic_num = 0 #update persistent cached data for restart cacheddata=(num_run_through,pic_num,last_file_change,next_check_tm) with open(config_file+".num","w") as f: json.dump(cacheddata,f,separators=(',',':')) # File Open and texture build try: temp=time.time() im = Image.open(iFiles[pic_num]) print("foto numero ",pic_num," time ",time.time()) except: print("Error Opening File",iFiles[pic_num]) continue # EXIF data and geolocation analysis # define some default values orientation = 1 # unrotated dt=None # will hold date from EXIF datestruct=None # will hold formatted date # Format metadata try: exif_data = im._getexif() except: exif_data=None try: orientation = int(exif_data[config.EXIF_ORIENTATION]) except: orientation = 1 try: dt = time.mktime(time.strptime(exif_data[config.EXIF_DATID], '%Y:%m:%d %H:%M:%S')) datestruct=time.localtime(dt) except: datestruct=None try: location = get_geo_name(exif_data) except Exception as e: # NB should really check error print('Error preparing geoname: ', e) location = None # Load and format image try: sfg = tex_load(im, orientation, (DISPLAY.width, DISPLAY.height)) except: next_pic_num += 1 # skip to next photo continue nexttm = tm+interval #Time points to next interval # Image Rendering if sbg is None: # first time through sbg = sfg slide.set_textures([sfg, sbg]) slide.unif[45:47] = slide.unif[42:44] # transfer front width and height factors to back slide.unif[51:53] = slide.unif[48:50] # transfer front width and height offsets wh_rat = (DISPLAY.width * sfg.iy) / (DISPLAY.height * sfg.ix) if (wh_rat > 1.0 and FIT) or (wh_rat <= 1.0 and not FIT): sz1, sz2, os1, os2 = 42, 43, 48, 49 else: sz1, sz2, os1, os2 = 43, 42, 49, 48 wh_rat = 1.0 / wh_rat slide.unif[sz1] = wh_rat slide.unif[sz2] = 1.0 slide.unif[os1] = (wh_rat - 1.0) * 0.5 slide.unif[os2] = 0.0 #transition if KENBURNS: xstep, ystep = (slide.unif[i] * 2.0 / interval for i in (48, 49)) slide.unif[48] = 0.0 slide.unif[49] = 0.0 kb_up = not kb_up # Prepare the different texts to be shown overlay_text= "" #this will host the text on screen if SHOW_LOCATION: #(and/or month-year) if location is not None: overlay_text += tidy_name(str(location)) #print(overlay_text) if datestruct is not None : overlay_text += " " + tidy_name(config.MES[datestruct.tm_mon - 1]) + "-" + str(datestruct.tm_year) #print(overlay_text) try: textblock.set_text(text_format="{}".format(overlay_text)) text.regen() except : #print("Wrong Overlay_text Format") textblock.set_text(" ") # print time on screen, blink separator every second if not paused : timetext=timetostring(time_dot,tm) else : timetext="PAUSA" timeblock.set_text(text_format="{}".format(timetext)) # manages transition if KENBURNS: t_factor = nexttm - tm if kb_up: t_factor = interval - t_factor slide.unif[48] = xstep * t_factor slide.unif[49] = ystep * t_factor if a <= 1.0: # transition is happening a += delta_alpha slide.unif[44] = a else: # Check if image files list has to be rebuilt (no transition on going, so no harm to image slide.set_textures([sfg, sfg]) if (num_run_through > config.NUMBEROFROUNDS) or (time.time() > next_check_tm) : #re-load images after running through them or exceeded time print("Refreshing Files list") next_check_tm = time.time() + check_dirs # Set up the next interval try: if check_changes(startdir): #rebuild files list if changes happened print("Re-Fetching images files, erase config file") with open(config_file,'w') as f : json.dump('',f) # creates an empty config file, forces directory reload iFiles, nFi = get_files(startdir,config_file,shuffle) next_pic_num = 0 else : print("No directory changes: do nothing") except: print("Error refreshing file list, keep old one") num_run_through = 0 #render the image slide.draw() #render the text text.draw() text2.draw() else: textblock.set_text("NO IMAGES SELECTED") textblock.colouring.set_colour(alpha=1.0) text.regen() text.draw() # Keyboard and button handling #delta=time.time()-86400.0 delta=0 if KEYBOARD: k = kbd.read() if k != -1: print("Key pressed", tm-nexttm) #nexttm = delta # print(tm - nexttm) if k==27 or quit: #ESC break if k==ord(' '): paused = not paused if k==ord('s'): # go back a picture nexttm = 0 next_pic_num -= 2 if next_pic_num < -1: next_pic_num = -1 nexttm = delta if k==ord('q'): #go forward nexttm = delta if k==ord('r') and paused: # rotate picture (only if paused) nexttm = delta im.close() #close file on disk try: with open(iFiles[pic_num],'rb') as tmp_file: #open file again to be used in exif context tmp_im = exif.Image(tmp_file) tmp_file.close() if (tmp_im.has_exif) : # If it has exif data, rotate it if it does not, do nothing save_file(iFiles[pic_num]) # Copy file to Backup folder tmp_im.orientation = rotate90CW(tmp_im.orientation) # changes EXIF data orientation parameter with open(iFiles[pic_num],'wb') as tmp_file: # Write the file with new exif orientation tmp_file.write(tmp_im.get_file()) next_pic_num -=1 # force reload on screen except: print("Error when rotating photo") # nexttm = delta if config.BUTTONS: #Handling of config.BUTTONS goes here if paused and (rotate_button.estado == 1 or rotate_button.estado == 2): # Need to be on pause rotate_button.estado = 0 nexttm = delta im.close() #close file on disk try: with open(iFiles[pic_num],'rb') as tmp_file: #open file again to be used in exif context tmp_im = exif.Image(tmp_file) tmp_file.close() if (tmp_im.has_exif) : # If it has exif data, rotate it if it does not, do nothing save_file(iFiles[pic_num]) # Copy file to Backup folder tmp_im.orientation = rotate90CW(tmp_im.orientation) # changes EXIF data orientation parameter with open(iFiles[pic_num],'wb') as tmp_file: # Write the file with new exif orientation tmp_file.write(tmp_im.get_file()) next_pic_num -=1 # force reload on screen except: print("Error when rotating photo") if pause_button.estado == 1 or pause_button.estado == 2 : # button was pressed #nexttm = delta paused = not paused pause_button.estado = 0 if back_button.estado == 1 or back_button.estado == 2 : nexttm = delta next_pic_num -= 2 if next_pic_num < -1: next_pic_num = -1 #nexttm = 0 #force reload back_button.estado = 0 if forward_button.estado == 1 or forward_button.estado == 2 : nexttm = delta forward_button.estado = 0 # All config.BUTTONS go to idle after processing them, regardless of state # WHILE LOOP ends here try: DISPLAY.loop_stop() except Exception as e: print("this was going to fail if previous try failed!") if KEYBOARD: kbd.close() DISPLAY.destroy()