def set_config_value(self, section, option, value): """Set camera configuration. This method don't send the updated configuration to the camera (avoid connection flooding if several values have to be changed) """ try: LOGGER.debug('Setting option %s/%s=%s', section, option, value) config = self._cam.get_config() child = config.get_child_by_name(section).get_child_by_name(option) if child.get_type() == gp.GP_WIDGET_RADIO: choices = [c for c in child.get_choices()] else: choices = None data_type = type(child.get_value()) value = data_type(value) # Cast value if choices and value not in choices: LOGGER.warning( "Invalid value '%s' for option %s (possible choices: %s), trying to set it anyway", value, option, choices) child.set_value(value) self._cam.set_config(config) except gp.GPhoto2Error as ex: LOGGER.error( 'Unsupported option %s/%s=%s (%s), configure your DSLR manually', section, option, value, ex)
def set_state(self, state_name): """Change state machine's active state """ try: # Perform any exit actions of the current state if self.active_state is not None: self.active_state.exit_actions() except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() state_name = self.failsafe_state.name else: raise if state_name not in self.states: raise ValueError( '"{}" not in registered states...'.format(state_name)) # Switch to the new state and perform its entry actions LOGGER.debug("Activate state '%s'", state_name) self.active_state = self.states[state_name] try: self.active_state.entry_actions() except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() self.set_state(self.failsafe_state.name) else: raise
def _create_or_retrieve_album(self): """Find albums created by this app to see if one matches album_title""" if self.album_name and self.album_id is None: for a in self.get_albums(True): if a["title"].lower() == self.album_name.lower(): self.album_id = a["id"] LOGGER.info("Uploading into EXISTING photo album -- '%s'", self.album_name) if self.album_id is None: # No matches, create new album create_album_body = json.dumps( {"album": { "title": self.album_name }}) # print(create_album_body) resp = self.session.post( 'https://photoslibrary.googleapis.com/v1/albums', create_album_body).json() LOGGER.debug("Server response: %s", resp) if "id" in resp: LOGGER.info("Uploading into NEW photo album -- '%s'", self.album_name) self.album_id = resp['id'] else: LOGGER.error( "Could not find or create photo album '%s'.\ Server Response: %s", self.album_name, resp) self.album_id = None
def process(self, events): """Let the current state do it's thing. """ # Only continue if there is an active state if self.active_state is None: return try: # Perform the actions of the active state hook = getattr(self.pm.hook, 'state_{}_do'.format(self.active_state)) hook(cfg=self.cfg, app=self.app, win=self.win, events=events) # Check conditions to activate the next state hook = getattr(self.pm.hook, 'state_{}_validate'.format(self.active_state)) new_state_name = hook(cfg=self.cfg, app=self.app, win=self.win, events=events) except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() new_state_name = self.failsafe_state else: raise if new_state_name is not None: self.set_state(new_state_name)
def set_state(self, state_name): """Change state machine's active state """ try: # Perform any exit actions of the current state if self.active_state is not None: hook = getattr(self.pm.hook, 'state_{}_exit'.format(self.active_state)) hook(cfg=self.cfg, app=self.app, win=self.win) except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() state_name = self.failsafe_state else: raise if state_name not in self.states: raise ValueError('"{}" not in registered states...'.format(state_name)) # Switch to the new state and perform its entry actions LOGGER.debug("Activate state '%s'", state_name) self.active_state = state_name try: hook = getattr(self.pm.hook, 'state_{}_enter'.format(self.active_state)) hook(cfg=self.cfg, app=self.app, win=self.win) except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() self.set_state(self.failsafe_state) else: raise
def set_config_value(self, section, option, value): """Set camera configuration. """ try: LOGGER.debug('Setting option %s/%s=%s', section, option, value) config = self._cam.get_config() child = config.get_child_by_name(section).get_child_by_name(option) if child.get_type() == gp.GP_WIDGET_RADIO: choices = [c for c in child.get_choices()] else: choices = None data_type = type(child.get_value()) value = data_type(value) # Cast value if choices and value not in choices: if value == 'Memory card' and 'card' in choices: value = 'card' # Fix for Sony ZV-1 elif value == 'Memory card' and 'card+sdram' in choices: value = 'card+sdram' # Fix for Sony ILCE-6400 else: LOGGER.warning( "Invalid value '%s' for option %s (possible choices: %s), trying to set it anyway", value, option, choices) child.set_value(value) self._cam.set_config(config) except gp.GPhoto2Error as ex: LOGGER.error( 'Unsupported option %s/%s=%s (%s), configure your DSLR manually', section, option, value, ex)
def __init__(self, client_id=None, credentials=None, activate=True): """Initialize GoogleUpload instance :param client_id: file download from google API :type client_id: file :param credentials: file create at first run to keep allow API use :type credentials: file :param activate: use to disable the plugin :type activate: bool """ self.scopes = [ 'https://www.googleapis.com/auth/photoslibrary', 'https://www.googleapis.com/auth/photoslibrary.sharing' ] # file to store authorization self.google_credentials = credentials # file with YOUR_CLIENT_ID and YOUR_CLIENT_SECRET generate on google self.client_id_file = client_id self.credentials = None self.session = None self.album_id = None self.album_name = None self.activate = activate if not os.path.exists(self.client_id_file) or os.path.getsize( self.client_id_file) == 0: LOGGER.error( "Can't load json file '%s' please check GOOGLE:client_id_file on pibooth config file (DISABLE PLUGIN)", self.client_id_file) self.activate = False if self.activate and self._is_internet(): self._get_authorized_session()
def main_loop(self): """Run the main game loop. """ try: fps = 40 clock = pygame.time.Clock() self._initialize() self._pm.hook.pibooth_startup(cfg=self._config, app=self) self._machine.set_state('wait') while True: events = list(pygame.event.get()) if self.find_quit_event(events): break if self.find_fullscreen_event(events): self._window.toggle_fullscreen() event = self.find_resize_event(events) if event: self._window.resize(event.size) if not self._menu and self.find_settings_event(events): self.camera.stop_preview() self.leds.off() self._menu = PiConfigMenu(self._window, self._config, self.count) self._menu.show() self.leds.blink(on_time=0.1, off_time=1) elif self._menu and self._menu.is_shown(): self._menu.process(events) elif self._menu and not self._menu.is_shown(): self.leds.off() self._initialize() self._machine.set_state('wait') self._menu = None else: self._machine.process(events) pygame.display.update() clock.tick( fps ) # Ensure the program will never run at more than <fps> frames per second except Exception as ex: LOGGER.error(str(ex), exc_info=True) LOGGER.error(get_crash_message()) finally: self._pm.hook.pibooth_cleanup(app=self) pygame.quit()
def create_album(self, album_name): """Create a new album and return its ID.""" LOGGER.info("Creating a new Google Photos album '%s'", album_name) create_album_body = json.dumps({"album": {"title": album_name}}) resp = self._session.post(self.URL + '/albums', create_album_body).json() LOGGER.debug("Google Photos server response: %s", resp) if "id" in resp: return resp['id'] LOGGER.error("Can not create Google Photos album '%s'", album_name) return None
def _on_keyboard_event(self, text): """Called after each option changed. """ if self._main_menu.is_enabled(): # Menu may have been closed selected = self._main_menu.get_current().get_selected_widget() if isinstance(selected, pgm.widgets.TextInput): if isinstance(selected, pgm.widgets.ColorInput): try: selected.set_value(tuple([int(c) for c in text.split(',')])) except Exception as ex: LOGGER.error("Invalid color value '%s' (%s)", text, ex) else: selected.set_value(text) selected.change()
def pibooth_startup(app, cfg): """Create the GooglePhotosUpload instance.""" app.previous_picture_url = None client_id_file = cfg.getpath('GOOGLE', 'client_id_file') if not client_id_file: LOGGER.debug( "No credentials file defined in [GOOGLE][client_id_file], upload deactivated" ) elif not os.path.exists(client_id_file): LOGGER.error( "No such file [GOOGLE][client_id_file]='%s', please check config", client_id_file) elif client_id_file and os.path.getsize(client_id_file) == 0: LOGGER.error( "Empty file [GOOGLE][client_id_file]='%s', please check config", client_id_file) else: app.google_photos = GooglePhotosApi(client_id_file)
def upload_now(file, crypt_name, url, pwd, app): """Upload a file to an ssh server param filename: Name and path of local file param url: The server address param pwd: Password for the user on the server """ upload_status = False try: with open(file, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()) payload = {'pass': pwd, 'image': encoded_string, 'filename': crypt_name} response = requests.post(url, json=payload) if response.ok and response.text == 'OK': upload_status = True else: LOGGER.error(response.text.encode('utf8')) except Exception as e: LOGGER.error("upload failed! " + str(e)) app.web_upload_sucessful = upload_status
def upload_photos(self, local_source_file, album_name, activate): """Funtion use to upload list of photos to google album :param local_source_file: PAth absolue to loca file to upload :type local_source_file: str :param album_name: name of albums to upload :type album_name: str :param activate: use to disable the upload :type activate: bool """ self.activate = activate # interrupt upload no internet if not self._is_internet(): LOGGER.error("Interrupt upload no internet connexion!!!!") return # if plugin is disable if not self.activate: LOGGER.error("Interrupt upload no activated !!!! (%s)", str(self.activate)) return LOGGER.info("In upload_photos Local (%s)", local_source_file) LOGGER.info("In upload_photos Remote (%s)", album_name) if not self.oc.put_file(album_name, local_source_file): LOGGER.error("Error while upload file to Nextcloud !!!!") return else: LOGGER.info("Photo upload to Nextcloud !!!!")
def ftp_upload(filename, uploadpath, serveraddress, user, pwd): """Upload a file to an ftp server param filename: Name and path of local file param uploadpath: Path on the ftp server to store file param serveraddress: The server address param user: Username for the server param pwd: Password for the user on the server """ ftp_status = False ftp = FTP() ftp.set_debuglevel(0) try: ftp.connect(serveraddress, 21) ftp.login(user, pwd) ftp.cwd(uploadpath) fp = open(filename, 'rb') ftp.storbinary('STOR %s' % os.path.basename(filename), fp, 1024) ftp_status = True fp.close() ftp.close() except Exception as e: LOGGER.error("FTP upload failed! " + str(e)) return ftp_status
def process(self, events): """Let the current state do it's thing """ # Only continue if there is an active state if self.active_state is None: return try: # Perform the actions of the active state self.active_state.do_actions(events) # Check conditions to activate the next state new_state_name = self.active_state.validate_transition(events) except Exception as ex: if self.failsafe_state and self.active_state != self.failsafe_state: LOGGER.error(str(ex)) if BlockConsoleHandler.is_debug(): traceback.print_exc() new_state_name = self.failsafe_state.name else: raise if new_state_name is not None: self.set_state(new_state_name)
def upload_photos(self, photo_file_list, album_name, activate): """Funtion use to upload list of photos to google album :param photo_file_list: list of photos name with full path :type photo_file_list: file :param album_name: name of albums to upload :type album_name: str :param activate: use to disable the upload :type activate: bool """ self.activate = activate # interrupt upload no internet if not self._is_internet(): LOGGER.error("Interrupt upload no internet connexion!!!!") return # if plugin is disable if not self.activate: return # plugin is disable at startup but activate after so check credential file elif not self.credentials: self._get_authorized_session() self.album_name = album_name self._create_or_retrieve_album() # interrupt upload if no album id can't read or create if self.album_name and not self.album_id: LOGGER.error("Interrupt upload album not found!!!!") return self.session.headers["Content-type"] = "application/octet-stream" self.session.headers["X-Goog-Upload-Protocol"] = "raw" for photo_file_name in photo_file_list: try: photo_file = open(photo_file_name, mode='rb') photo_bytes = photo_file.read() except OSError as err: LOGGER.error("Could not read file '%s' -- %s", photo_file_name, err) continue self.session.headers["X-Goog-Upload-File-Name"] = os.path.basename( photo_file_name) LOGGER.info("Uploading photo -- '%s'", photo_file_name) upload_token = self.session.post( 'https://photoslibrary.googleapis.com/v1/uploads', photo_bytes) if (upload_token.status_code == 200) and upload_token.content: create_body = json.dumps( { "albumId": self.album_id, "newMediaItems": [{ "description": "", "simpleMediaItem": { "uploadToken": upload_token.content.decode() } }] }, indent=4) resp = self.session.post( 'https://photoslibrary.googleapis.com/v1/mediaItems:batchCreate', create_body).json() LOGGER.debug("Server response: %s", resp) if "newMediaItemResults" in resp: status = resp["newMediaItemResults"][0]["status"] if status.get("code") and (status.get("code") > 0): LOGGER.error("Could not add '%s' to library -- %s", os.path.basename(photo_file_name), status["message"]) else: LOGGER.info("Added '%s' to library and album '%s' ", os.path.basename(photo_file_name), album_name) else: LOGGER.error( "Could not add '%s' to library. Server Response -- %s", os.path.basename(photo_file_name), resp) else: LOGGER.error("Could not upload '%s'. Server Response -- %s", os.path.basename(photo_file_name), upload_token) try: del self.session.headers["Content-type"] del self.session.headers["X-Goog-Upload-Protocol"] del self.session.headers["X-Goog-Upload-File-Name"] except KeyError: pass
def upload(self, filename, album_name): """Upload a photo file to the given Google Photos album. :param filename: photo file full path :type filename: str :param album_name: name of albums to upload :type album_name: str :returns: URL of the uploaded photo :rtype: str """ photo_url = None if not self.is_reachable(): LOGGER.error( "Google Photos upload failure: no internet connexion!") return photo_url if not self._credentials: # Plugin was disabled at startup but activated after self._session = self._get_authorized_session() album_id = self.get_album_id(album_name) if not album_id: album_id = self.create_album(album_name) if not album_id: LOGGER.error("Google Photos upload failure: album '%s' not found!", album_name) return photo_url self._session.headers["Content-type"] = "application/octet-stream" self._session.headers["X-Goog-Upload-Protocol"] = "raw" with open(filename, mode='rb') as fp: data = fp.read() self._session.headers["X-Goog-Upload-File-Name"] = os.path.basename( filename) LOGGER.info("Uploading picture '%s' to Google Photos", filename) upload_token = self._session.post(self.URL + '/uploads', data) if upload_token.status_code == 200 and upload_token.content: create_body = json.dumps({ "albumId": album_id, "newMediaItems": [{ "description": "", "simpleMediaItem": { "uploadToken": upload_token.content.decode() } }] }) resp = self._session.post(self.URL + '/mediaItems:batchCreate', create_body).json() LOGGER.debug("Google Photos server response: %s", resp) if "newMediaItemResults" in resp: status = resp["newMediaItemResults"][0]["status"] if status.get("code") and (status.get("code") > 0): LOGGER.error( "Google Photos upload failure: can not add '%s' to library: %s", os.path.basename(filename), status["message"]) else: photo_url = resp["newMediaItemResults"][0][ 'mediaItem'].get('productUrl') LOGGER.info( "Google Photos upload successful: '%s' added to album '%s'", os.path.basename(filename), album_name) else: LOGGER.error( "Google Photos upload failure: can not add '%s' to library", os.path.basename(filename)) elif upload_token.status_code != 200: LOGGER.error( "Google Photos upload failure: can not connect to '%s' (HTTP error %s)", self.URL, upload_token.status_code) else: LOGGER.error( "Google Photos upload failure: no response content from server '%s'", self.URL) try: del self._session.headers["Content-type"] del self._session.headers["X-Goog-Upload-Protocol"] del self._session.headers["X-Goog-Upload-File-Name"] except KeyError: pass return photo_url
def state_failsafe_enter(self, win): win.show_oops() self.failed_view_timer.start() LOGGER.error(get_crash_message())