Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
helgeerbe committed Jan 20, 2022
2 parents 5574fde + 00f3345 commit e6e8b04
Show file tree
Hide file tree
Showing 11 changed files with 560 additions and 149 deletions.
32 changes: 30 additions & 2 deletions picframe/config/configuration_example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ viewer:
show_text_sz: 40 # default=40, text character size
show_text: "title caption name date folder location" # default="title caption name date folder location", show text, include combination of words: title, caption name, date, location, folder
text_justify: "L" # text justification L, C or R
text_bkg_hgt: 0.25 # default=0.25 (0.0-1.0), percentage of screen height for text background texture
fit: False # default=False, True => scale image so all visible and leave 'gaps'
# False => crop image so no 'gaps'
kenburns: False # default=False, will set fit->False and blur_edges->False
Expand All @@ -38,6 +39,9 @@ viewer:
clock_text_sz: 120 # default=120, clock character size
clock_format: "%I:%M" # default="%I:%M", strftime format for clock string

menu_text_sz: 40 # default=40, menu character size
menu_autohide_tm: 10.0 # default=10.0, time in seconds to show menu before auto hiding (0 disables auto hiding)

model:
pic_dir: "~/Pictures" # default="~/Pictures", root folder for images
deleted_pictures: "~/DeletedPictures" # move deleted pictures here
Expand Down Expand Up @@ -82,7 +86,6 @@ model:
log_level: "WARNING" # default=WARNING, could beDEBUG, INFO, WARNING, ERROR, CRITICAL
log_file: "" # default="" for debugging set this to the path to a file. NB logging messages will
# appended indefinitely so don't forget this. You will need to tidy it up later
use_kbd: False # default=False, just for debug or console start. Crashing when started with systemd

mqtt:
use_mqtt: False # default=False. Set True true, to enable mqtt
Expand All @@ -92,11 +95,36 @@ mqtt:
password: "your_password" # password for mqtt user
tls: "/path/to/your/ca.crt" # filename including path to your ca.crt. If not used, must be set to "" !!!!
device_id: "picframe" # default="picframe" unique id of device. change if there is more than one PictureFrame
device_url: "" # if use_http==True, set url to picframe config page. Must be a valid url, or "" otherwise home assistant runs in an error.

http:
use_http: False # default=False. Set True to enable http NB THIS SERVER IS FOR LOCAL NETWORK AND SHOULD NOT BE EXPOSED TO EXTERNAL ACCESS
path: "~/picframe_data/html" # path to where html files are located
port: 9000 # port used to serve pages by http server < 1024 requires root which is *bad* idea
use_ssl: False
keyfile: "path/to/key.pem" # private-key
certfile: "path/to/cert.pem" # server certificate
certfile: "path/to/cert.pem" # server certificate

peripherals:
input_type: null # default=null, valid options: {null, "keyboard", "touch", "mouse"}
buttons:
pause: # pause/unpause the show
enable: True # default=True
label: "Pause" # default="Pause"
shortcut: " " # default=" "
display_off: # turn off the display (when off, any input from selected peripheral will turn it back on)
enable: True # default=True
label: "Display off" # default="Display off"
shortcut: "o" # default="o"
location: # shows or hides location information
enable: False # default=False
label: "Location" # default="Location"
shortcut: "l" # default="l"
exit: # exit PictureFrame
enable: False # default=False
label: "Exit" # default="Exit"
shortcut: "e" # default="e"
power_down: # power down the device, uses sudo
enable: False # default=False
label: "Power down" # default="Power down"
shortcut: "p" # default="p"
19 changes: 15 additions & 4 deletions picframe/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import os
import signal
import sys
from picframe.interface_peripherals import InterfacePeripherals

def make_date(txt):
dt = txt.replace('/',':').replace('-',':').replace(',',':').replace('.',':').split(':')
Expand Down Expand Up @@ -42,16 +43,18 @@ def __init__(self, model, viewer):
self.__model = model
self.__viewer = viewer
self.__paused = False
self.__force_navigate = False
self.__next_tm = 0
self.__date_from = make_date('1901/12/15') # TODO This seems to be the minimum date to be handled by date functions
self.__date_to = make_date('2038/1/1')
self.__location_filter = ""
self.__where_clauses = {}
self.__sort_clause = "exif_datetime ASC"
self.publish_state = lambda x, y: None
self.__keep_looping = True
self.keep_looping = True
self.__location_filter = ''
self.__tags_filter = ''
self.__interface_peripherals = None
self.__shutdown_complete = False

@property
Expand All @@ -70,11 +73,13 @@ def paused(self, val:bool):
def next(self):
self.__next_tm = 0
self.__viewer.reset_name_tm()
self.__force_navigate = True

def back(self):
self.__model.set_next_file_to_previous_file()
self.__next_tm = 0
self.__viewer.reset_name_tm()
self.__force_navigate = True

def delete(self):
self.__model.delete_file()
Expand Down Expand Up @@ -196,6 +201,7 @@ def brightness(self):
@brightness.setter
def brightness(self, val):
self.__viewer.set_brightness(float(val))
self.__next_tm = 0

@property
def matting_images(self):
Expand All @@ -204,6 +210,7 @@ def matting_images(self):
@matting_images.setter
def matting_images(self, val):
self.__viewer.set_matting_images(float(val))
self.__next_tm = 0

@property
def location_filter(self):
Expand Down Expand Up @@ -276,7 +283,7 @@ def loop(self): #TODO exit loop gracefully and call image_cache.stop()
signal.signal(signal.SIGINT, self.__signal_handler)

#next_check_tm = time.time() + self.__model.get_model_config()['check_dir_tm']
while self.__keep_looping:
while self.keep_looping:

#if self.__next_tm == 0: #TODO double check why these were set when next_tm == 0
# time_delay = 1 # must not be 0
Expand All @@ -287,8 +294,9 @@ def loop(self): #TODO exit loop gracefully and call image_cache.stop()

tm = time.time()
pics = None #get_next_file returns a tuple of two in case paired portraits have been specified
if not self.paused and tm > self.__next_tm:
if not self.paused and tm > self.__next_tm or self.__force_navigate:
self.__next_tm = tm + self.__model.time_delay
self.__force_navigate = False
pics = self.__model.get_next_file()
if pics[0] is None:
self.__next_tm = 0 # skip this image file moved or otherwise not on db
Expand All @@ -311,13 +319,16 @@ def loop(self): #TODO exit loop gracefully and call image_cache.stop()
break
if skip_image:
self.__next_tm = 0
self.__interface_peripherals.check_input()
self.__shutdown_complete = True

def start(self):
self.__viewer.slideshow_start()
self.__interface_peripherals = InterfacePeripherals(self.__model, self.__viewer, self)

def stop(self):
self.__keep_looping = False
self.keep_looping = False
self.__interface_peripherals.stop()
while not self.__shutdown_complete:
time.sleep(0.05) # block until main loop has stopped
self.__model.stop_image_chache() # close db tidily (blocks till closed)
Expand Down
3 changes: 2 additions & 1 deletion picframe/image_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ def __update_schema(self, required_db_schema_version):
# Finally, update the db's schema version stamp to the app's requested version
self.__db.execute('DELETE FROM db_info')
self.__db.execute('INSERT INTO db_info VALUES(?)', (required_db_schema_version,))

self.__db.commit()

# --- Returns a set of folders matching any of
# - Found on disk, but not currently in the 'folder' table
Expand All @@ -356,6 +356,7 @@ def __get_modified_folders(self):
out_of_date_folders = []
sql_select = "SELECT * FROM folder WHERE name = ?"
for dir in [d[0] for d in os.walk(self.__picture_dir, followlinks=self.__follow_links)]:
if os.path.basename(dir)[0] == '.': continue # ignore hidden folders
mod_tm = int(os.stat(dir).st_mtime)
found = self.__db.execute(sql_select, (dir,)).fetchone()
if not found or found['last_modified'] < mod_tm or found['missing'] == 1:
Expand Down
18 changes: 4 additions & 14 deletions picframe/interface_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ def do_GET(self):
for subkey in self.server._setters:
message[subkey] = getattr(self.server._controller, subkey)
elif key in dir(self.server._controller):
if key in self.server._setters: # can get info back from controller TODO
message[key] = getattr(self.server._controller, key)
if value != "": # parse_qsl can return empty string for value when just querying
lwr_val = value.lower()
if lwr_val in ("true", "on", "yes"): # this only works for simple values *not* json style kwargs
Expand All @@ -98,6 +96,8 @@ def do_GET(self):
getattr(self.server._controller, key)(**json.loads(value))
except Exception as e:
message['ERROR'] = 'Excepton:{}>{};'.format(key, e)
if key in self.server._setters: # can get info back from controller TODO
message[key] = getattr(self.server._controller, key)

self.wfile.write(bytes(json.dumps(message), "utf8"))
self.connection.close()
Expand Down Expand Up @@ -148,18 +148,8 @@ def __init__(self, controller, html_path, pic_dir, no_files_img, port=9000):
controller_class = controller.__class__
self._setters = [method for method in dir(controller_class)
if 'setter' in dir(getattr(controller_class, method))]
self.__keep_looping = True
self.__shutdown_completed = False
t = threading.Thread(target=self.__loop)
t = threading.Thread(target=self.serve_forever)
t.start()

def __loop(self):
while self.__keep_looping:
self.handle_request()
time.sleep(0.1)
self.__shutdown_completed = True

def stop(self):
self.__keep_looping = False
while not self.__shutdown_completed:
time.sleep(0.05) # function blocking until loop stopped
self.shutdown()
51 changes: 0 additions & 51 deletions picframe/interface_kbd.py

This file was deleted.

Loading

0 comments on commit e6e8b04

Please sign in to comment.