First steps. Deleted alot, added even more.
1
.gitignore
vendored
|
@ -14,3 +14,4 @@
|
||||||
/Calendar/DataSourceInterface.pyc
|
/Calendar/DataSourceInterface.pyc
|
||||||
/Calendar/CalendarInterface.pyc
|
/Calendar/CalendarInterface.pyc
|
||||||
/Calendar/CalendarEvent.pyc
|
/Calendar/CalendarEvent.pyc
|
||||||
|
/Calendar/design_exported_old.png
|
||||||
|
|
|
@ -22,17 +22,12 @@ seperator = im_open(opath+'seperator.jpeg').convert('L')
|
||||||
no_response= im_open(opath+'cloud-no-response.jpeg')
|
no_response= im_open(opath+'cloud-no-response.jpeg')
|
||||||
sunriseicon = im_open(opath+'wi-sunrise.jpeg')
|
sunriseicon = im_open(opath+'wi-sunrise.jpeg')
|
||||||
sunseticon = im_open(opath+'wi-sunset.jpeg')
|
sunseticon = im_open(opath+'wi-sunset.jpeg')
|
||||||
windicon = im_open(opath+'wi-strong-wind.jpeg')
|
windicon = im_open(opath+'wi-strong-wind.jpeg')#
|
||||||
|
|
||||||
wiconplace = (0, 0)
|
datetime_locals = {
|
||||||
tempplace = (299, 0)
|
"de" : "de_DE.UTF-8",
|
||||||
humplace = (299, 35)
|
"en" : "en_US.UTF-8"
|
||||||
seperatorplace = (0, 72)
|
}
|
||||||
monthplace = (0, 74)
|
|
||||||
weekplace = (3, 134)
|
|
||||||
windiconspace = (79, 0)
|
|
||||||
sunriseplace = (214, 0)
|
|
||||||
sunsetplace = (214, 35)
|
|
||||||
|
|
||||||
e_col = 70
|
e_col = 70
|
||||||
date_col = 0
|
date_col = 0
|
|
@ -1,5 +1,5 @@
|
||||||
from DebugInterface import DebugInterface
|
from DebugInterface import DebugInterface
|
||||||
from icon_positions_locations import weathericons
|
from Assets import weathericons
|
||||||
|
|
||||||
class DebugConsole (DebugInterface):
|
class DebugConsole (DebugInterface):
|
||||||
"""Defines concrete console export of debug objects"""
|
"""Defines concrete console export of debug objects"""
|
||||||
|
|
35
Calendar/DesignEntity.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
from PIL import Image, ImageOps, ImageDraw
|
||||||
|
|
||||||
|
class DesignEntity (object):
|
||||||
|
"""General entity that can be drawn on to a panel design or
|
||||||
|
other design entities."""
|
||||||
|
def __init__ (self, size):
|
||||||
|
self.size = size
|
||||||
|
self.pos = (0, 0)
|
||||||
|
self.__init_image__()
|
||||||
|
self.is_bitmap = False
|
||||||
|
|
||||||
|
def __init_image__ (self, color = 'white'):
|
||||||
|
self.__image__ = Image.new('L', self.size, color=color)
|
||||||
|
|
||||||
|
def get_image (self):
|
||||||
|
self.__finish_image__()
|
||||||
|
return self.__image__
|
||||||
|
|
||||||
|
def draw (self, subimage, pos):
|
||||||
|
self.__image__.paste(subimage, pos)
|
||||||
|
|
||||||
|
def draw_bitmap (self, subimage, pos):
|
||||||
|
ImageDraw.Draw(self.__image__).bitmap(pos, subimage)
|
||||||
|
|
||||||
|
def draw_design (self, entity):
|
||||||
|
if entity.is_bitmap:
|
||||||
|
self.draw_bitmap(entity.get_image(), entity.pos)
|
||||||
|
else:
|
||||||
|
self.draw(entity.get_image(), entity.pos)
|
||||||
|
|
||||||
|
def draw_image (self, path, pos):
|
||||||
|
self.draw(Image.open(path), pos)
|
||||||
|
|
||||||
|
def __finish_image__ (self):
|
||||||
|
pass
|
|
@ -8,25 +8,19 @@ If you have any questions, feel free to open an issue at Github.
|
||||||
Copyright by aceisace
|
Copyright by aceisace
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import calendar
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from Assets import datetime_locals
|
||||||
|
import locale
|
||||||
from DebugConsole import DebugConsole
|
from DebugConsole import DebugConsole
|
||||||
|
|
||||||
debug = DebugConsole()
|
|
||||||
|
|
||||||
from settings import *
|
from settings import *
|
||||||
from icon_positions_locations import *
|
from MonthOvPanel import MonthOvPanel
|
||||||
|
from WeatherHeaderDesign import WeatherHeaderDesign
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
|
||||||
import OwmForecasts
|
import OwmForecasts
|
||||||
import IcalEvents
|
import IcalEvents
|
||||||
try:
|
|
||||||
from urllib.request import urlopen
|
|
||||||
except Exception as e:
|
|
||||||
debug.print_line("Something didn't work right, maybe you're offline?" + e.reason)
|
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, datetime_locals[language])
|
||||||
|
debug = DebugConsole()
|
||||||
output_adapters = []
|
output_adapters = []
|
||||||
|
|
||||||
if render_to_file:
|
if render_to_file:
|
||||||
|
@ -44,11 +38,6 @@ if render_to_display:
|
||||||
epd = Epd7in5Adapter.Epd7in5Adapter()
|
epd = Epd7in5Adapter.Epd7in5Adapter()
|
||||||
output_adapters.append(epd)
|
output_adapters.append(epd)
|
||||||
|
|
||||||
EPD_WIDTH = epd.width
|
|
||||||
EPD_HEIGHT = epd.height
|
|
||||||
font = ImageFont.truetype(path + 'Assistant-Regular.ttf', 18)
|
|
||||||
im_open = Image.open
|
|
||||||
|
|
||||||
"""Main loop starts from here"""
|
"""Main loop starts from here"""
|
||||||
def main ():
|
def main ():
|
||||||
while True:
|
while True:
|
||||||
|
@ -60,205 +49,125 @@ def main ():
|
||||||
|
|
||||||
for i in range(1):
|
for i in range(1):
|
||||||
debug.print_line('_________Starting new loop___________' + '\n')
|
debug.print_line('_________Starting new loop___________' + '\n')
|
||||||
"""At the following hours (midnight, midday and 6 pm), perform
|
debug.print_line('Date:'+ time.strftime('%a %d %b %y') + ', time: ' + time.strftime('%H:%M') + '\n')
|
||||||
a calibration of the display's colours"""
|
|
||||||
|
|
||||||
if hour in calibrate_hours:
|
if hour in calibrate_hours:
|
||||||
for output in output_adapters:
|
for output in output_adapters:
|
||||||
output.calibrate()
|
output.calibrate()
|
||||||
|
|
||||||
debug.print_line('Date:'+ time.strftime('%a %d %b %y') + ', time: ' + time.strftime('%H:%M') + '\n')
|
design = MonthOvPanel((epd.width, epd.height))
|
||||||
|
|
||||||
"""Create a blank white page, for debugging, change mode to
|
|
||||||
to 'RGB' and and save the image by uncommenting the image.save
|
|
||||||
line at the bottom"""
|
|
||||||
image = Image.new('L', (EPD_HEIGHT, EPD_WIDTH), 'white')
|
|
||||||
draw = (ImageDraw.Draw(image)).bitmap
|
|
||||||
|
|
||||||
"""Draw the icon with the current month's name"""
|
|
||||||
image.paste(im_open(mpath + str(time.strftime("%B") + '.jpeg')), monthplace)
|
|
||||||
|
|
||||||
"""Draw a line seperating the weather and Calendar section"""
|
|
||||||
image.paste(seperator, seperatorplace)
|
|
||||||
|
|
||||||
"""Draw the icons with the weekday-names (Mon, Tue...) and
|
|
||||||
draw a circle on the current weekday"""
|
|
||||||
if (week_starts_on == "Monday"):
|
|
||||||
calendar.setfirstweekday(calendar.MONDAY)
|
|
||||||
image.paste(weekmon, weekplace)
|
|
||||||
draw(weekdaysmon[(time.strftime("%a"))], weekday)
|
|
||||||
|
|
||||||
if (week_starts_on == "Sunday"):
|
|
||||||
calendar.setfirstweekday(calendar.SUNDAY)
|
|
||||||
image.paste(weeksun, weekplace)
|
|
||||||
draw(weekdayssun[(time.strftime("%a"))], weekday)
|
|
||||||
|
|
||||||
"""Using the built-in calendar function, draw icons for each
|
|
||||||
number of the month (1,2,3,...28,29,30)"""
|
|
||||||
cal = calendar.monthcalendar(time.year, time.month)
|
|
||||||
#debug.print_line(cal) #-uncomment for debugging with incorrect dates
|
|
||||||
|
|
||||||
for numbers in cal[0]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['a' + str(cal[0].index(numbers) + 1)])
|
|
||||||
for numbers in cal[1]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['b' + str(cal[1].index(numbers) + 1)])
|
|
||||||
for numbers in cal[2]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['c' + str(cal[2].index(numbers) + 1)])
|
|
||||||
for numbers in cal[3]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['d' + str(cal[3].index(numbers) + 1)])
|
|
||||||
for numbers in cal[4]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['e' + str(cal[4].index(numbers) + 1)])
|
|
||||||
try:
|
|
||||||
for numbers in cal[5]:
|
|
||||||
image.paste(im_open(dpath + str(numbers) + '.jpeg'), positions['f' + str(cal[5].index(numbers) + 1)])
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
"""Custom function to display text on the E-Paper.
|
|
||||||
Tuple refers to the x and y coordinates of the E-Paper display,
|
|
||||||
with (0, 0) being the top left corner of the display."""
|
|
||||||
def write_text (box_width, box_height, text, tuple):
|
|
||||||
text_width, text_height = font.getsize(text)
|
|
||||||
if (text_width, text_height) > (box_width, box_height):
|
|
||||||
raise ValueError('Sorry, your text is too big for the box')
|
|
||||||
else:
|
|
||||||
x = int((box_width / 2) - (text_width / 2))
|
|
||||||
y = int((box_height / 2) - (text_height / 2))
|
|
||||||
space = Image.new('L', (box_width, box_height), color=255)
|
|
||||||
ImageDraw.Draw(space).text((x, y), text, fill=0, font=font)
|
|
||||||
image.paste(space, tuple)
|
|
||||||
|
|
||||||
""" Handling Openweathermap API"""
|
|
||||||
debug.print_line("Connecting to Openweathermap API servers...")
|
debug.print_line("Connecting to Openweathermap API servers...")
|
||||||
owm = OwmForecasts.OwmForecasts(api_key, units=units)
|
owm = OwmForecasts.OwmForecasts(api_key)
|
||||||
if owm.is_available() is True:
|
design.add_weather(OwmForecasts.OwmForecasts(api_key))
|
||||||
forecast = owm.get_today_forecast(location)
|
|
||||||
debug.print_forecast(forecast)
|
|
||||||
|
|
||||||
if forecast.units == "metric":
|
output_adapters[0].render(design)
|
||||||
write_text(50, 35, forecast.air_temperature + " °C", (334, 0))
|
return
|
||||||
write_text(100, 35, forecast.wind_speed + " km/h", (114, 0))
|
|
||||||
|
|
||||||
if forecast.units == "imperial":
|
|
||||||
write_text(50, 35, forecast.air_temperature + " °F", (334, 0))
|
|
||||||
write_text(100, 35, forecast.wind_speed + " mph", (114, 0))
|
|
||||||
|
|
||||||
if hours == "24":
|
|
||||||
sunrisetime = str(forecast.sunrise.strftime('%H:%M'))
|
|
||||||
sunsettime = str(forecast.sunset.strftime('%H:%M'))
|
|
||||||
|
|
||||||
if hours == "12":
|
|
||||||
sunrisetime = str(forecast.sunrise.strftime('%I:%M'))
|
|
||||||
sunsettime = str(forecast.sunset.strftime('%I:%M'))
|
|
||||||
|
|
||||||
"""Drawing the fetched weather icon"""
|
|
||||||
image.paste(im_open(wpath + weathericons[forecast.icon] + '.jpeg'), wiconplace)
|
|
||||||
|
|
||||||
"""Drawing the fetched temperature"""
|
|
||||||
image.paste(tempicon, tempplace)
|
|
||||||
|
|
||||||
"""Drawing the fetched humidity"""
|
|
||||||
image.paste(humicon, humplace)
|
|
||||||
write_text(50, 35, forecast.air_humidity + " %", (334, 35))
|
|
||||||
|
|
||||||
"""Drawing the fetched sunrise time"""
|
|
||||||
image.paste(sunriseicon, sunriseplace)
|
|
||||||
write_text(50, 35, sunrisetime, (249, 0))
|
|
||||||
|
|
||||||
"""Drawing the fetched sunset time"""
|
|
||||||
image.paste(sunseticon, sunsetplace)
|
|
||||||
write_text(50, 35, sunsettime, (249, 35))
|
|
||||||
|
|
||||||
"""Drawing the wind icon"""
|
|
||||||
image.paste(windicon, windiconspace)
|
|
||||||
|
|
||||||
"""Write a short weather description"""
|
|
||||||
write_text(144, 35, forecast.short_description, (70, 35))
|
|
||||||
|
|
||||||
else:
|
|
||||||
image.paste(no_response, wiconplace)
|
|
||||||
|
|
||||||
"""Filter upcoming events from your iCalendar/s"""
|
|
||||||
debug.print_line('Fetching events from your calendar' + '\n')
|
|
||||||
|
|
||||||
events_cal = IcalEvents.IcalEvents(ical_urls)
|
|
||||||
|
|
||||||
for event in events_cal.get_month_events():
|
|
||||||
debug.print_event(event)
|
|
||||||
|
|
||||||
upcoming = events_cal.get_upcoming_events()
|
|
||||||
events_this_month = events_cal.get_month_events()
|
|
||||||
events_this_month = [event.begin_datetime.day for event in events_this_month]
|
|
||||||
|
|
||||||
def takeDate (elem):
|
|
||||||
return elem.begin_datetime
|
|
||||||
|
|
||||||
upcoming.sort(key=takeDate)
|
|
||||||
|
|
||||||
del upcoming[4:]
|
|
||||||
# uncomment the following 2 lines to display the fetched events
|
|
||||||
# from your iCalendar
|
|
||||||
debug.print_line('Upcoming events:')
|
|
||||||
debug.print_line(upcoming)
|
|
||||||
debug.print_line('Month events:')
|
|
||||||
debug.print_line(events_this_month)
|
|
||||||
|
|
||||||
#Credit to Hubert for suggesting truncating event names
|
|
||||||
def write_text_left (box_width, box_height, text, tuple):
|
|
||||||
text_width, text_height = font.getsize(text)
|
|
||||||
while (text_width, text_height) > (box_width, box_height):
|
|
||||||
text=text[0:-1]
|
|
||||||
text_width, text_height = font.getsize(text)
|
|
||||||
y = int((box_height / 2) - (text_height / 2))
|
|
||||||
space = Image.new('L', (box_width, box_height), color=255)
|
|
||||||
ImageDraw.Draw(space).text((0, y), text, fill=0, font=font)
|
|
||||||
image.paste(space, tuple)
|
|
||||||
|
|
||||||
"""Write event dates and names on the E-Paper"""
|
|
||||||
for dates in range(len(upcoming)):
|
|
||||||
write_text(70, 25, (upcoming[dates].begin_datetime.strftime('%d %b')), date_positions['d' + str(dates + 1)])
|
|
||||||
|
|
||||||
for events in range(len(upcoming)):
|
|
||||||
write_text_left(314, 25, (upcoming[events].title), event_positions['e' + str(events + 1)])
|
|
||||||
|
|
||||||
"""Draw smaller squares on days with events"""
|
|
||||||
for numbers in events_this_month:
|
|
||||||
if numbers in cal[0]:
|
|
||||||
draw(positions['a' + str(cal[0].index(numbers) + 1)], eventicon)
|
|
||||||
if numbers in cal[1]:
|
|
||||||
draw(positions['b' + str(cal[1].index(numbers) + 1)], eventicon)
|
|
||||||
if numbers in cal[2]:
|
|
||||||
draw(positions['c' + str(cal[2].index(numbers) + 1)], eventicon)
|
|
||||||
if numbers in cal[3]:
|
|
||||||
draw(positions['d' + str(cal[3].index(numbers) + 1)], eventicon)
|
|
||||||
if numbers in cal[4]:
|
|
||||||
draw(positions['e' + str(cal[4].index(numbers) + 1)], eventicon)
|
|
||||||
try:
|
|
||||||
if numbers in cal[5]:
|
|
||||||
draw(positions['f' + str(cal[5].index(numbers) + 1)], eventicon)
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
"""Draw a larger square on today's date"""
|
|
||||||
today = time.day
|
#"""Filter upcoming events from your iCalendar/s"""
|
||||||
if today in cal[0]:
|
#debug.print_line('Fetching events from your calendar' + '\n')
|
||||||
draw(positions['a' + str(cal[0].index(today) + 1)], dateicon)
|
|
||||||
if today in cal[1]:
|
#events_cal = IcalEvents.IcalEvents(ical_urls)
|
||||||
draw(positions['b' + str(cal[1].index(today) + 1)], dateicon)
|
|
||||||
if today in cal[2]:
|
#for event in events_cal.get_month_events():
|
||||||
draw(positions['c' + str(cal[2].index(today) + 1)], dateicon)
|
# debug.print_event(event)
|
||||||
if today in cal[3]:
|
|
||||||
draw(positions['d' + str(cal[3].index(today) + 1)], dateicon)
|
#upcoming = events_cal.get_upcoming_events()
|
||||||
if today in cal[4]:
|
#events_this_month = events_cal.get_month_events()
|
||||||
draw(positions['e' + str(cal[4].index(today) + 1)], dateicon)
|
#events_this_month = [event.begin_datetime.day for event in events_this_month]
|
||||||
try:
|
|
||||||
if today in cal[5]:
|
#def takeDate (elem):
|
||||||
draw(positions['f' + str(cal[5].index(today) + 1)], dateicon)
|
# return elem.begin_datetime
|
||||||
except IndexError:
|
|
||||||
pass
|
#upcoming.sort(key=takeDate)
|
||||||
|
|
||||||
|
#del upcoming[4:]
|
||||||
|
## uncomment the following 2 lines to display the fetched events
|
||||||
|
## from your iCalendar
|
||||||
|
#debug.print_line('Upcoming events:')
|
||||||
|
#debug.print_line(upcoming)
|
||||||
|
#debug.print_line('Month events:')
|
||||||
|
#debug.print_line(events_this_month)
|
||||||
|
|
||||||
|
##Credit to Hubert for suggesting truncating event names
|
||||||
|
#def write_text_left (box_width, box_height, text, tuple):
|
||||||
|
# text_width, text_height = font.getsize(text)
|
||||||
|
# while (text_width, text_height) > (box_width, box_height):
|
||||||
|
# text=text[0:-1]
|
||||||
|
# text_width, text_height = font.getsize(text)
|
||||||
|
# y = int((box_height / 2) - (text_height / 2))
|
||||||
|
# space = Image.new('L', (box_width, box_height), color=255)
|
||||||
|
# ImageDraw.Draw(space).text((0, y), text, fill=0, font=font)
|
||||||
|
# image.paste(space, tuple)
|
||||||
|
|
||||||
|
#"""Write event dates and names on the E-Paper"""
|
||||||
|
#for dates in range(len(upcoming)):
|
||||||
|
# write_text(70, 25, (upcoming[dates].begin_datetime.strftime('%d %b')), date_positions['d' + str(dates + 1)])
|
||||||
|
|
||||||
|
#for events in range(len(upcoming)):
|
||||||
|
# write_text_left(314, 25, (upcoming[events].title), event_positions['e' + str(events + 1)])
|
||||||
|
|
||||||
|
#"""Draw smaller squares on days with events"""
|
||||||
|
#for numbers in events_this_month:
|
||||||
|
# if numbers in cal[0]:
|
||||||
|
# draw(positions['a' + str(cal[0].index(numbers) + 1)], eventicon)
|
||||||
|
# if numbers in cal[1]:
|
||||||
|
# draw(positions['b' + str(cal[1].index(numbers) + 1)], eventicon)
|
||||||
|
# if numbers in cal[2]:
|
||||||
|
# draw(positions['c' + str(cal[2].index(numbers) + 1)], eventicon)
|
||||||
|
# if numbers in cal[3]:
|
||||||
|
# draw(positions['d' + str(cal[3].index(numbers) + 1)], eventicon)
|
||||||
|
# if numbers in cal[4]:
|
||||||
|
# draw(positions['e' + str(cal[4].index(numbers) + 1)], eventicon)
|
||||||
|
# try:
|
||||||
|
# if numbers in cal[5]:
|
||||||
|
# draw(positions['f' + str(cal[5].index(numbers) + 1)], eventicon)
|
||||||
|
# except IndexError:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
#"""Draw a larger square on today's date"""
|
||||||
|
#today = time.day
|
||||||
|
#if today in cal[0]:
|
||||||
|
# draw(positions['a' + str(cal[0].index(today) + 1)], dateicon)
|
||||||
|
#if today in cal[1]:
|
||||||
|
# draw(positions['b' + str(cal[1].index(today) + 1)], dateicon)
|
||||||
|
#if today in cal[2]:
|
||||||
|
# draw(positions['c' + str(cal[2].index(today) + 1)], dateicon)
|
||||||
|
#if today in cal[3]:
|
||||||
|
# draw(positions['d' + str(cal[3].index(today) + 1)], dateicon)
|
||||||
|
#if today in cal[4]:
|
||||||
|
# draw(positions['e' + str(cal[4].index(today) + 1)], dateicon)
|
||||||
|
#try:
|
||||||
|
# if today in cal[5]:
|
||||||
|
# draw(positions['f' + str(cal[5].index(today) + 1)], dateicon)
|
||||||
|
#except IndexError:
|
||||||
|
# pass
|
||||||
|
|
||||||
for output in output_adapters:
|
for output in output_adapters:
|
||||||
output.render(image)
|
output.render(design)
|
||||||
|
|
||||||
debug.print_line("Finished rendering")
|
debug.print_line("Finished rendering")
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from PIL import Image, ImageDraw
|
||||||
|
|
||||||
class Epd7in5Adapter (EpdAdapter):
|
class Epd7in5Adapter (EpdAdapter):
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
super(Epd7in5Adapter, self).__init__(640, 384)
|
super(Epd7in5Adapter, self).__init__(384, 640)
|
||||||
|
|
||||||
def display_frame (self, frame_buffer):
|
def display_frame (self, frame_buffer):
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
self.send_command(DATA_START_TRANSMISSION_1)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from PIL import Image, ImageDraw
|
||||||
|
|
||||||
class Epd7in5bAdapter (EpdAdapter):
|
class Epd7in5bAdapter (EpdAdapter):
|
||||||
def __init__ (self):
|
def __init__ (self):
|
||||||
super(Epd7in5bAdapter, self).__init__(640, 384)
|
super(Epd7in5bAdapter, self).__init__(384, 640)
|
||||||
|
|
||||||
def display_frame (self, frame_buffer):
|
def display_frame (self, frame_buffer):
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
self.send_command(DATA_START_TRANSMISSION_1)
|
||||||
|
|
|
@ -71,7 +71,7 @@ class EpdAdapter (DisplayAdapter):
|
||||||
|
|
||||||
print('Converting image to data and sending it to the display')
|
print('Converting image to data and sending it to the display')
|
||||||
print('This may take a while...' + '\n')
|
print('This may take a while...' + '\n')
|
||||||
prepared_image = design.rotate(270, expand=1)
|
prepared_image = design.get_image().rotate(270, expand=1)
|
||||||
self.display_frame(self.get_frame_buffer(prepared_image))
|
self.display_frame(self.get_frame_buffer(prepared_image))
|
||||||
|
|
||||||
# Powering off the E-Paper until the next loop
|
# Powering off the E-Paper until the next loop
|
||||||
|
|
|
@ -3,11 +3,11 @@ from DisplayAdapter import DisplayAdapter
|
||||||
class ImageFileAdapter (DisplayAdapter):
|
class ImageFileAdapter (DisplayAdapter):
|
||||||
"""Saves design to an image file, can be used for debugging"""
|
"""Saves design to an image file, can be used for debugging"""
|
||||||
def __init__ (self, file_path = ""):
|
def __init__ (self, file_path = ""):
|
||||||
super(ImageFileAdapter, self).__init__(640, 384)
|
super(ImageFileAdapter, self).__init__(384, 640)
|
||||||
self.file_path = file_path
|
self.file_path = file_path
|
||||||
|
|
||||||
def render (self, design):
|
def render (self, design):
|
||||||
design.save(self.file_path + 'design_exported.png')
|
design.get_image().save(self.file_path + 'design_exported.png')
|
||||||
|
|
||||||
def calibrate (self):
|
def calibrate (self):
|
||||||
pass
|
pass
|
85
Calendar/MonthOvPanel.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
from PanelDesign import PanelDesign
|
||||||
|
from Assets import *
|
||||||
|
from settings import *
|
||||||
|
import calendar
|
||||||
|
from datetime import datetime
|
||||||
|
from WeatherHeaderDesign import WeatherHeaderDesign
|
||||||
|
from PIL import ImageDraw
|
||||||
|
from TextDesign import TextDesign
|
||||||
|
|
||||||
|
weatherheadersize = (1,0.113)
|
||||||
|
seperatorplace = (0, 0.113)
|
||||||
|
monthplace = (0, 0.116)
|
||||||
|
weekplace = (0, 0.209)
|
||||||
|
monthboxsize = (1, 0.085)
|
||||||
|
daynumberboxsize = (0.143, 0.143)
|
||||||
|
daynumbersize = 28
|
||||||
|
monthtextsize = 40
|
||||||
|
monthovposition = (0, 0.225)
|
||||||
|
monthovsize = (1, 0.5)
|
||||||
|
|
||||||
|
class MonthOvPanel (PanelDesign):
|
||||||
|
"""Overview that focuses on the current month and
|
||||||
|
some additional information in the bottom."""
|
||||||
|
def __init__ (self, size):
|
||||||
|
super(MonthOvPanel, self).__init__(size)
|
||||||
|
self.__first_render__()
|
||||||
|
|
||||||
|
def __first_render__ (self):
|
||||||
|
time = datetime.now()
|
||||||
|
|
||||||
|
self.__draw_month_name__()
|
||||||
|
self.__draw_seperator__()
|
||||||
|
"""Draw the icons with the weekday-names (Mon, Tue...) and
|
||||||
|
draw a circle on the current weekday"""
|
||||||
|
#if (week_starts_on == "Monday"):
|
||||||
|
# calendar.setfirstweekday(calendar.MONDAY)
|
||||||
|
# self.draw(weekmon, self.__abs_pos__(weekplace))
|
||||||
|
# self.draw_bitmap(weekday, weekdaysmon[(time.strftime("%a"))])
|
||||||
|
#elif (week_starts_on == "Sunday"):
|
||||||
|
# calendar.setfirstweekday(calendar.SUNDAY)
|
||||||
|
# self.draw(weeksun, self.__abs_pos__(weekplace))
|
||||||
|
# self.draw_bitmap(weekday, weekdayssun[(time.strftime("%a"))])
|
||||||
|
"""Using the built-in calendar function, draw icons for each
|
||||||
|
number of the month (1,2,3,...28,29,30)"""
|
||||||
|
cal = calendar.monthcalendar(time.year, time.month)
|
||||||
|
for week in cal:
|
||||||
|
for numbers in week:
|
||||||
|
self.__draw_day_number__(numbers, self.__get_day_pos__(cal.index(week), week.index(numbers)))
|
||||||
|
|
||||||
|
def add_weather (self, weather):
|
||||||
|
self.draw_design(WeatherHeaderDesign(self.__abs_pos__(weatherheadersize), weather))
|
||||||
|
|
||||||
|
def add_calendar (self, calendar):
|
||||||
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
|
def add_rssfeed (self, rss):
|
||||||
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
|
def __abs_pos__(self, pos):
|
||||||
|
return (int(pos[0] * self.size[0]), int(pos[1] * self.size[1]))
|
||||||
|
|
||||||
|
def __draw_seperator__(self):
|
||||||
|
"""Draw a line seperating the weather and Calendar section"""
|
||||||
|
ImageDraw.Draw(self.__image__).line( [self.__abs_pos__(seperatorplace), self.__abs_pos__((1, seperatorplace[1]))], fill='red', width=5)
|
||||||
|
|
||||||
|
def __draw_day_number__(self, number, pos):
|
||||||
|
if number <= 0:
|
||||||
|
return
|
||||||
|
txt = TextDesign(self.__abs_pos__(daynumberboxsize), fontsize=daynumbersize, text=str(number), verticalalignment="center", horizontalalignment="center")
|
||||||
|
txt.pos = pos
|
||||||
|
self.draw_design(txt)
|
||||||
|
|
||||||
|
def __draw_month_name__(self):
|
||||||
|
"""Draw the icon with the current month's name"""
|
||||||
|
month = datetime.now().strftime("%B")
|
||||||
|
txt = TextDesign(self.__abs_pos__(monthboxsize), fontsize=monthtextsize, text=month, verticalalignment="center", horizontalalignment="center")
|
||||||
|
txt.pos = self.__abs_pos__(monthplace)
|
||||||
|
self.draw_design(txt)
|
||||||
|
|
||||||
|
def __get_day_pos__ (self, week_in_month, day_of_week):
|
||||||
|
maxwidth, maxheight = self.__abs_pos__(monthovsize)
|
||||||
|
partialwidth = maxwidth / 7
|
||||||
|
partialheight = maxheight / 5
|
||||||
|
posx, posy = self.__abs_pos__(monthovposition)
|
||||||
|
return (posx + day_of_week * partialwidth, posy + week_in_month * partialheight)
|
|
@ -1,11 +1,9 @@
|
||||||
class PanelDesign(object):
|
from DesignEntity import DesignEntity
|
||||||
"""Defined general interface for panel designs."""
|
|
||||||
def set_size(self, width, height):
|
|
||||||
self.width = width
|
|
||||||
self.height = height
|
|
||||||
|
|
||||||
def get_image (self):
|
class PanelDesign (DesignEntity):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
"""Defined general interface for panel designs."""
|
||||||
|
def __init__ (self, size):
|
||||||
|
super(PanelDesign, self).__init__(size)
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather (self, weather):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
38
Calendar/TextDesign.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from DesignEntity import DesignEntity
|
||||||
|
from PIL import ImageFont, ImageDraw, ImageOps
|
||||||
|
from Assets import path
|
||||||
|
|
||||||
|
class TextDesign (DesignEntity):
|
||||||
|
"""Object that manages all information relevant to text
|
||||||
|
and prints it to an image"""
|
||||||
|
def __init__ (self, size, font = "Assistant-Regular.ttf", fontsize = 12, text = "", horizontalalignment = "left", verticalalignment = "top"):
|
||||||
|
super(TextDesign, self).__init__(size)
|
||||||
|
self.font_family = font
|
||||||
|
self.font_size = fontsize
|
||||||
|
self.text = text
|
||||||
|
self.horizontal_alignment = horizontalalignment
|
||||||
|
self.vertical_alignment = verticalalignment
|
||||||
|
self.is_bitmap = True
|
||||||
|
|
||||||
|
def __finish_image__ (self):
|
||||||
|
self.__init_image__()
|
||||||
|
self.__font__ = ImageFont.truetype(path + self.font_family, self.font_size)
|
||||||
|
pos = self.__pos_from_alignment__()
|
||||||
|
ImageDraw.Draw(self.__image__).text(pos, self.text, fill=0, font=self.__font__)
|
||||||
|
self.__image__ = ImageOps.invert(self.__image__)
|
||||||
|
|
||||||
|
def __pos_from_alignment__ (self):
|
||||||
|
width, height = self.__font__.getsize(self.text)
|
||||||
|
x, y = 0, 0
|
||||||
|
|
||||||
|
if self.vertical_alignment == "center":
|
||||||
|
y = int((self.size[1] / 2) - (height / 2))
|
||||||
|
elif self.vertical_alignment == "bottom":
|
||||||
|
y = int(self.size[1] - height)
|
||||||
|
|
||||||
|
if self.horizontal_alignment == "center":
|
||||||
|
x = int((self.size[0] / 2) - (width / 2))
|
||||||
|
elif self.vertical_alignment == "right":
|
||||||
|
x = int(self.size[0] - width)
|
||||||
|
|
||||||
|
return (x, y)
|
65
Calendar/WeatherHeaderDesign.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
from DesignEntity import DesignEntity
|
||||||
|
from Assets import *
|
||||||
|
from TextDesign import TextDesign
|
||||||
|
from settings import units, hours, location
|
||||||
|
|
||||||
|
wiconplace = (0, 0)
|
||||||
|
tempplace = (0.779, 0)
|
||||||
|
humplace = (0.779, 0.486)
|
||||||
|
windiconspace = (0.206, 0)
|
||||||
|
sunriseplace = (0.55, 0)
|
||||||
|
sunsetplace = (0.55, 0.486)
|
||||||
|
|
||||||
|
class WeatherHeaderDesign (DesignEntity):
|
||||||
|
"""Defines a top area that displays basic weather information"""
|
||||||
|
def __init__ (self, size, weather):
|
||||||
|
super(WeatherHeaderDesign, self).__init__(size)
|
||||||
|
self.__weather__ = weather
|
||||||
|
self.__first_render__()
|
||||||
|
|
||||||
|
def __first_render__ (self):
|
||||||
|
if self.__weather__.is_available() is False:
|
||||||
|
self.__render_missing_connection__()
|
||||||
|
return
|
||||||
|
|
||||||
|
cur_weather = self.__weather__.get_today_forecast(location)
|
||||||
|
|
||||||
|
temperature = cur_weather.air_temperature + " " + self.__get_unit__(("°C", "°F"))
|
||||||
|
windspeed = cur_weather.wind_speed + " " + self.__get_unit__(("km/h", "mph"))
|
||||||
|
|
||||||
|
self.__draw_text__(temperature, self.__abs_pos__((0.87, 0)), (50,35))
|
||||||
|
self.__draw_text__(windspeed, self.__abs_pos__((0.297, 0)), (100,35))
|
||||||
|
self.__draw_text__(self.__get_time__(cur_weather.sunrise), self.__abs_pos__((0.64,0)), (50,35))
|
||||||
|
self.__draw_text__(self.__get_time__(cur_weather.sunset), self.__abs_pos__((0.64,0.486)), (50,35))
|
||||||
|
self.__draw_text__(cur_weather.air_humidity + " %", self.__abs_pos__((0.87,0.486)), (50,35))
|
||||||
|
self.__draw_text__(cur_weather.short_description, self.__abs_pos__((0.182,0.486)), (144,35))
|
||||||
|
|
||||||
|
self.draw(windicon, self.__abs_pos__(windiconspace))
|
||||||
|
self.draw(sunseticon, self.__abs_pos__(sunsetplace))
|
||||||
|
self.draw(sunriseicon, self.__abs_pos__(sunriseplace))
|
||||||
|
self.draw(humicon, self.__abs_pos__(humplace))
|
||||||
|
self.draw(tempicon, self.__abs_pos__(tempplace))
|
||||||
|
self.draw_image(wpath + weathericons[cur_weather.icon] + '.jpeg', self.__abs_pos__(wiconplace))
|
||||||
|
|
||||||
|
def __render_missing_connection__ (self):
|
||||||
|
self.draw_image(no_response, self.__abs_pos__(wiconplace))
|
||||||
|
|
||||||
|
def __abs_pos__ (self, pos):
|
||||||
|
return (int(pos[0] * self.size[0]), int(pos[1] * self.size[1]))
|
||||||
|
|
||||||
|
def __draw_text__ (self, text, pos, size):
|
||||||
|
txt = TextDesign(size, fontsize=18, text=text, verticalalignment="center", horizontalalignment="center")
|
||||||
|
txt.pos = pos
|
||||||
|
self.draw_design(txt)
|
||||||
|
|
||||||
|
def __get_unit__ (self, tuple):
|
||||||
|
if units == "metric":
|
||||||
|
return tuple[0]
|
||||||
|
else:
|
||||||
|
return tuple[1]
|
||||||
|
|
||||||
|
def __get_time__ (self, time):
|
||||||
|
if hours == "24":
|
||||||
|
return time.strftime('%H:%M')
|
||||||
|
else:
|
||||||
|
return time.strftime('%I:%M')
|
Before Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 7.2 KiB |