Пример #1
0
class GoProProxy:
    maxRetries = 3

    # init
    def __init__(self, log_level=logging.INFO):
        # setup log
        log_file = '/var/log/gopro-proxy.log'
        log_format = '%(asctime)s   %(message)s'
        logging.basicConfig(format=log_format, level=log_level)

        # file logging
        fh = logging.FileHandler(log_file)
        fh.setLevel(log_level)
        fh.setFormatter(logging.Formatter(log_format))
        logger = logging.getLogger()
        logger.setLevel(log_level)
        logger.addHandler(fh)

        # setup camera
        self.camera = GoProHero()
        self.snapshots = os.environ.get('GOPRO_SNAPSHOTS', True)

        # setup wireless
        interface = os.environ.get('GOPRO_WIFI_INTERFACE', None)
        self.wireless = Wireless(interface)

    # connect to the camera's network
    def connect(self, camera):
        func_str = 'GoProProxy.connect({}, {})'.format(
            camera.ssid, camera.password)

        # jump to a new network only if needed
        if self.wireless.current() != camera.ssid:
            self.wireless.connect(
                ssid=camera.ssid, password=camera.password)

        # evaluate connection request
        if self.wireless.current() == camera.ssid:
            # reconfigure the password in the camera instance
            self.camera.password(camera.password)

            logging.info('{}{}{}'.format(Fore.CYAN, func_str, Fore.RESET))
            return True
        else:
            logging.info('{}{} - network not found{}'.format(
                Fore.YELLOW, func_str, Fore.RESET))
            return False

    # send command
    def sendCommand(self, command):
        result = False

        # make sure we are connected to the right camera
        if self.connect(command.camera):
            # try to send the command, a few times if needed
            i = 0
            while i < self.maxRetries and result is False:
                result = self.camera.command(command.command, command.value)
                i += 1
        else:
            # mini-status update if we couldn't connect
            command.camera.last_attempt = timezone.now()
            command.camera.summary = 'notfound'

        # did we successfully talk to the camera?
        self.updateCounters(command.camera, result)
        command.camera.save()

        # save result
        command.time_completed = timezone.now()
        command.save()

    # get status
    def getStatus(self, camera):
        # make sure we are connected to the right camera
        camera.last_attempt = timezone.now()
        connected = self.connect(camera)

        # could we find the camera?
        if connected:
            # update counters
            camera.last_update = camera.last_attempt
            self.updateCounters(camera, True)

            # try to get the camera's status
            status = self.camera.status()
            camera.summary = status['summary']

            # extend existing status if possible
            if camera.status != '':
                # allows us to retain knowledge of settings when powered off
                try:
                    old_status = json.loads(camera.status)
                    if old_status != '':
                        old_status.update(status)
                        status = old_status
                except ValueError:
                    logging.info('{}{} - existing status malformed{}'.format(
                        Fore.YELLOW, 'GoProProxy.getStatus()', Fore.RESET))

            # save status to camera
            camera.status = json.dumps(status)

            # grab snapshot when the camera is powered on
            if self.snapshots is True and 'power' in status \
                    and status['power'] == 'on':
                camera.save()
                image = self.camera.image()
                if image is not False:
                    camera.image = image
                    camera.image_last_update = camera.last_attempt
        else:
            # update counters
            self.updateCounters(camera, False)

            # update status
            camera.summary = 'notfound'

        # save result
        camera.save()

    def updateCounters(self, camera, success):
        camera.connection_attempts += 1
        if success is not True:
            camera.connection_failures += 1

    # main loop
    def run(self):
        logging.info('{}GoProProxy.run(){}'.format(Fore.GREEN, Fore.RESET))
        logging.info('Wifi interface: {}, wifi driver: {}'.format(
            self.wireless.interface(), self.wireless.driver()))
        logging.info('Attempt snapshots: {}'.format(self.snapshots))

        # keep running until we land on Mars
        # keep the contents of this loop short (limit to one cmd/status or one
        # status) so that we can quickly catch KeyboardInterrupt, SystemExit
        while 'people' != 'on Mars':

            # PRIORITY 1: send command for the current network on if possible
            commands = Command.objects.filter(
                time_completed__isnull=True,
                camera__ssid__exact=self.wireless.current())
            if len(commands) > 0:
                self.sendCommand(commands[0])

                # get the status now because it is cheap
                if self.wireless.current() == commands[0].camera.ssid:
                    self.getStatus(commands[0].camera)

            # PRIORITY 2: send the oldest command still in the queue
            else:
                commands = Command.objects.filter(
                    time_completed__isnull=True).order_by('-date_added')
                if len(commands) > 0:
                    self.sendCommand(commands[0])

                    # get the status now because it is cheap
                    if self.wireless.current() == commands[0].camera.ssid:
                        self.getStatus(commands[0].camera)

                # PRIORITY 3: check status of the most stale camera
                else:
                    cameras = Camera.objects.all().order_by('last_attempt')
                    if len(cameras) > 0:
                        self.getStatus(cameras[0])

            # protect the cpu in the event that there was nothing to do
            time.sleep(0.1)