コード例 #1
0
    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
コード例 #2
0
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)
コード例 #3
0
    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)
コード例 #4
0
    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
コード例 #5
0
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)
コード例 #6
0
    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
コード例 #7
0
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()