def handleEvents(self): if self.cleanConfig: logging.info('Change of configuration, flush data and restart') # We need to expunge any pending image now # so we get fresh data to show the user if self.doMemoryForget: self.services.memoryForget(forgetHistory=True) self.doMemoryForget = False if self.doClearCache: CacheManager.empty(self.settings.CACHEFOLDER) self.doClearCache = False if self.imageCurrent: self.imageCurrent = None self.skipPreloadedImage = True self.imageOnScreen = False self.display.clear() self.cleanConfig = False if self.doControl == "nextImage": #just skip delay and show the next (preloaded) image pass elif self.doControl == "prevImage": self.skipPreloadedImage = True self.ignoreRandomize = True if self.services.prevImage(): self.delayer.set() elif self.doControl == "nextAlbum": self.skipPreloadedImage = True self.services.nextAlbum() self.delayer.set() elif self.doControl == "prevAlbum": self.skipPreloadedImage = True self.services.prevAlbum() self.delayer.set() self.doControl = None
def cfg_rotation(orient): if orient is None: return jsonify({'rotation': sysconfig.getDisplayOrientation()}) else: if orient >= 0 and orient < 360: sysconfig.setDisplayOrientation(orient) CacheManager.empty(settings.CACHEFOLDER) return jsonify({'rotation': sysconfig.getDisplayOrientation()}) abort(500)
def __init__(self, cmdline): self.void = open(os.devnull, 'wb') random.seed(long(time.clock())) self.emulator = cmdline.emulate if self.emulator: self.enableEmulation() if cmdline.basedir is not None: self.changeRoot(cmdline.basedir) if not path().validate(): sys.exit(255) self.cacheMgr = CacheManager() self.settingsMgr = settings() self.driverMgr = drivers() self.displayMgr = display(self.emulator) self.serviceMgr = ServiceManager(self.settingsMgr, self.cacheMgr) self.colormatch = colormatch( self.settingsMgr.get('colortemp-script'), 2700) # 2700K = Soft white, lowest we'll go self.slideshow = slideshow(self.displayMgr, self.settingsMgr, self.colormatch) self.timekeeperMgr = timekeeper(self.displayMgr.enable, self.slideshow.start) self.powerMgr = shutdown(self.settingsMgr.getUser('shutdown-pin')) # Validate all settings, prepopulate with defaults if needed self.validateSettings() self.cacheMgr.validate() self.cacheMgr.enableCache( self.settingsMgr.getUser('enable-cache') == 1) # Tie all the services together as needed self.timekeeperMgr.setConfiguration( self.settingsMgr.getUser('display-on'), self.settingsMgr.getUser('display-off')) self.timekeeperMgr.setAmbientSensitivity( self.settingsMgr.getUser('autooff-lux'), self.settingsMgr.getUser('autooff-time')) self.timekeeperMgr.setPowermode(self.settingsMgr.getUser('powersave')) self.colormatch.setUpdateListener(self.timekeeperMgr.sensorListener) self.slideshow.setQueryPower(self.timekeeperMgr.getDisplayOn) self.slideshow.setServiceManager(self.serviceMgr) self.slideshow.setCacheManager(self.cacheMgr) self.slideshow.setCountdown(cmdline.countdown) # Prep the webserver self.setupWebserver(cmdline.listen, cmdline.port) # Force display to desired user setting self.displayMgr.enable(True, True)
def presentation(self): cacheFolder = self.settings.CACHEFOLDER lessImportantDirs = ["blurred", "zoomed"] CacheManager.createDirs(cacheFolder, subDirs=lessImportantDirs) CacheManager.garbageCollect(cacheFolder, lessImportantDirs) self.services.getServices(readyOnly=True) if not slideshow.SHOWN_IP: self.startupScreen() logging.info('Starting presentation') i = 0 while True: i += 1 time_process = time.time() # Avoid showing images if the display is off if self.queryPowerFunc is not None and self.queryPowerFunc( ) is False: logging.info("Display is off, exit quietly") break if (i % 100) == 0: CacheManager.garbageCollect(cacheFolder, lessImportantDirs) displaySize = { 'width': self.settings.getUser('width'), 'height': self.settings.getUser('height'), 'force_orientation': self.settings.getUser('force_orientation') } randomize = (not self.ignoreRandomize) and bool( self.settings.getUser('randomize_images')) self.ignoreRandomize = False result = self.services.servicePrepareNextItem( cacheFolder, self.supportedFormats, displaySize, randomize) if self.handleErrors(result): continue filenameOriginal = os.path.join(cacheFolder, result["id"]) filenameProcessed = self.process(filenameOriginal) if filenameProcessed is None: continue time_process = time.time() - time_process self.delayNextImage(time_process) self.handleEvents() self.showPreloadedImage(filenameProcessed, result["mimetype"], result["id"]) self.thread = None
def cfg_keyvalue(key, value): global powermanagement # Depending on PUT/GET we will either change or read # values. If key is unknown, then this call fails with 404 if key is not None: if settings.getUser(key) is None: abort(404) return if request.method == 'PUT': status = True if key == "keywords": # Keywords has its own API abort(404) return settings.setUser(key, value) if key in ['display-driver']: drv = settings.getUser('display-driver') if drv == 'none': drv = None special = drivers.activate(drv) if special is None: settings.setUser('display-driver', 'none') settings.setUser('display-special', None) status = False else: settings.setUser('display-special', special) if key in ['timezone']: # Make sure we convert + to / settings.setUser('timezone', value.replace('+', '/')) helper.timezoneSet(settings.getUser('timezone')) if key in ['resolution', 'tvservice']: width, height, tvservice = display.setConfiguration( value, settings.getUser('display-special')) settings.setUser('tvservice', tvservice) settings.setUser('width', width) settings.setUser('height', height) display.enable(True, True) CacheManager.empty(settings.CACHEFOLDER) if key in ['display-on', 'display-off']: timekeeper.setConfiguration(settings.getUser('display-on'), settings.getUser('display-off')) if key in ['autooff-lux', 'autooff-time']: timekeeper.setAmbientSensitivity(settings.getUser('autooff-lux'), settings.getUser('autooff-time')) if key in ['powersave']: timekeeper.setPowermode(settings.getUser('powersave')) if key in ['shutdown-pin']: powermanagement.stopmonitor() powermanagement = shutdown(settings.getUser('shutdown-pin')) if key in ['imagesizing', 'randomize_images']: slideshow.createEvent("settingsChange") settings.save() return jsonify({'status': status}) elif request.method == 'GET': if key is None: return jsonify(settings.getUser()) else: return jsonify({key: settings.getUser(key)}) abort(404)
def selectImageFromAlbum(self, destinationDir, supportedMimeTypes, displaySize, randomize): # chooses an album and selects an image from that album --> return {'id':, 'mimetype':, 'error':, 'source':} # if no (new) images can be found --> return None keywordList = list(self.getKeywords()) keywordCount = len(keywordList) if keywordCount == 0: return { 'id': None, 'mimetype': None, 'source': None, 'error': 'No albums have been specified' } if randomize: index = self.getRandomKeywordIndex() else: index = self.keywordIndex # if current keywordList[index] does not contain any new images --> just run through all albums for i in range(0, keywordCount): if not randomize and (index + i) >= keywordCount: # (non-random image order): return if the last album is exceeded --> serviceManager should use next service break self.keywordIndex = (index + i) % keywordCount keyword = keywordList[self.keywordIndex] # a provider-specific implementation for 'getImagesFor' is obligatory! images = self.getImagesFor(keyword) if images is None: logging.warning( 'Function returned None, this is used sometimes when a temporary error happens. Still logged' ) self.imageIndex = 0 continue if len(images) > 0 and 'error' in images[0]: return images[0] self._STATE["_NUM_IMAGES"][keyword] = len(images) if len(images) == 0: self.imageIndex = 0 continue elif any(key not in images[0].keys() for key in ['id', 'url', 'mimetype', 'source', 'filename']): return { 'id': None, 'mimetype': None, 'source': None, 'error': 'You haven\'t implemented "getImagesFor" correctly (some keys are missing)' } self.saveState() image = self.selectImage(images, supportedMimeTypes, displaySize, randomize) if image is None: self.imageIndex = 0 continue filename = os.path.join(destinationDir, image['id']) if CacheManager.useCachedImage(filename): if image['mimetype'] is None: image['mimetype'] = helper.getMimeType(filename) return { 'id': image['id'], 'mimetype': image['mimetype'], 'source': image['source'], 'error': None } # you should implement 'addUrlParams' if the provider allows 'width' / 'height' parameters! recommendedSize = self.calcRecommendedSize(image['size'], displaySize) url = self.addUrlParams(image['url'], recommendedSize, displaySize) try: result = self.requestUrl(url, destination=filename) except requests.exceptions.RequestException as e: # catch any exception caused by malformed url, unstable internet connection, ... that would otherwise break the entire photoframe logging.debug(str(e)) if helper.getIP() is None: return { 'id': None, 'mimetype': None, 'source': None, 'error': "No internet connection!" } return { 'id': None, 'mimetype': None, 'source': url, 'error': "Unable to download image!\nServer might be unavailable or URL could be broken:\n%s" % url } if result['status'] == 200: if image['mimetype'] is None: image['mimetype'] = result['mimetype'] return { 'id': image['id'], 'mimetype': image['mimetype'], 'source': image['source'], 'error': None } else: return { 'id': None, 'mimetype': None, 'source': None, 'error': "%d: Unable to download image!" % result['status'] } self.resetIndices() return None
class Photoframe: def __init__(self, cmdline): self.void = open(os.devnull, 'wb') random.seed(long(time.clock())) self.emulator = cmdline.emulate if self.emulator: self.enableEmulation() if cmdline.basedir is not None: self.changeRoot(cmdline.basedir) if not path().validate(): sys.exit(255) self.eventMgr = Events() self.eventMgr.add('Hello world') self.cacheMgr = CacheManager() self.settingsMgr = settings() self.displayMgr = display(self.emulator) # Validate all settings, prepopulate with defaults if needed self.validateSettings() self.imageHistory = ImageHistory(self.settingsMgr) self.driverMgr = drivers() self.serviceMgr = ServiceManager(self.settingsMgr, self.cacheMgr) self.colormatch = colormatch(self.settingsMgr.get('colortemp-script'), 2700) # 2700K = Soft white, lowest we'll go self.slideshow = slideshow(self.displayMgr, self.settingsMgr, self.colormatch, self.imageHistory) self.timekeeperMgr = timekeeper() self.timekeeperMgr.registerListener(self.displayMgr.enable) self.powerMgr = shutdown(self.settingsMgr.getUser('shutdown-pin')) self.cacheMgr.validate() self.cacheMgr.enableCache(self.settingsMgr.getUser('enable-cache') == 1) # Tie all the services together as needed self.timekeeperMgr.setConfiguration(self.settingsMgr.getUser('display-on'), self.settingsMgr.getUser('display-off')) self.timekeeperMgr.setAmbientSensitivity(self.settingsMgr.getUser('autooff-lux'), self.settingsMgr.getUser('autooff-time')) self.timekeeperMgr.setPowermode(self.settingsMgr.getUser('powersave')) self.colormatch.setUpdateListener(self.timekeeperMgr.sensorListener) self.timekeeperMgr.registerListener(self.slideshow.shouldShow) self.slideshow.setServiceManager(self.serviceMgr) self.slideshow.setCacheManager(self.cacheMgr) self.slideshow.setCountdown(cmdline.countdown) # Prep the webserver self.setupWebserver(cmdline.listen, cmdline.port) # Force display to desired user setting self.displayMgr.enable(True, True) def updating(self, x, y): self.slideshow.stop(self.updating_continue) def updating_continue(self): self.displayMgr.message('Updating software', False) self.webServer.stop() logging.debug('Entering hover mode, waiting for update to finish') while True: # This is to allow our subprocess to run! time.sleep(30) def _loadRoute(self, module, klass, *vargs): module = importlib.import_module('routes.' + module) klass = getattr(module, klass) route = eval('klass()') route.setupex(*vargs) self.webServer.registerHandler(route) def setupWebserver(self, listen, port): test = WebServer(port=port, listen=listen) self.webServer = test self._loadRoute('settings', 'RouteSettings', self.powerMgr, self.settingsMgr, self.driverMgr, self.timekeeperMgr, self.displayMgr, self.cacheMgr, self.slideshow) self._loadRoute('keywords', 'RouteKeywords', self.serviceMgr, self.slideshow) self._loadRoute('orientation', 'RouteOrientation', self.cacheMgr) self._loadRoute('overscan', 'RouteOverscan', self.cacheMgr) self._loadRoute('maintenance', 'RouteMaintenance', self.emulator, self.driverMgr, self.slideshow) self._loadRoute('details', 'RouteDetails', self.displayMgr, self.driverMgr, self.colormatch, self.slideshow, self.serviceMgr, self.settingsMgr) self._loadRoute('upload', 'RouteUpload', self.settingsMgr, self.driverMgr) self._loadRoute('oauthlink', 'RouteOAuthLink', self.serviceMgr, self.slideshow) self._loadRoute('service', 'RouteService', self.serviceMgr, self.slideshow) self._loadRoute('control', 'RouteControl', self.slideshow) self._loadRoute('events', 'RouteEvents', self.eventMgr) def validateSettings(self): if not self.settingsMgr.load(): # First run, grab display settings from current mode current = self.displayMgr.current() if current is not None: logging.info('No display settings, using: %s' % repr(current)) self.settingsMgr.setUser('tvservice', '%s %s HDMI' % (current['mode'], current['code'])) self.settingsMgr.save() else: logging.info('No display attached?') if self.settingsMgr.getUser('timezone') == '': self.settingsMgr.setUser('timezone', helper.timezoneCurrent()) self.settingsMgr.save() width, height, tvservice = self.displayMgr.setConfiguration(self.settingsMgr.getUser('tvservice'), self.settingsMgr.getUser('display-special')) self.settingsMgr.setUser('tvservice', tvservice) self.settingsMgr.setUser('width', width) self.settingsMgr.setUser('height', height) self.settingsMgr.save() def changeRoot(self, newRoot): if newRoot is None: return newpath = os.path.join(newRoot, '/') logging.info('Altering basedir to %s', newpath) path().reassignBase(newpath) def enableEmulation(self): logging.info('Running in emulation mode, settings are stored in /tmp/photoframe/') if not os.path.exists('/tmp/photoframe'): os.mkdir('/tmp/photoframe') path().reassignBase('/tmp/photoframe/') path().reassignConfigTxt('extras/config.txt') def start(self): signal.signal(signal.SIGHUP, lambda x, y: self.updating(x,y)) self.slideshow.start() self.webServer.start()