mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Make Yi platform async (#14944)
* Conversion complete * Updated requirements * Got rid of 3.6-specific syntax * Removed more 3.6-specific syntax * Contributor-requested changes
This commit is contained in:
parent
08adfd87f7
commit
d549e26a9b
@ -11,11 +11,13 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
|
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
|
||||||
from homeassistant.components.ffmpeg import DATA_FFMPEG
|
from homeassistant.components.ffmpeg import DATA_FFMPEG
|
||||||
from homeassistant.const import (CONF_HOST, CONF_NAME, CONF_PATH,
|
from homeassistant.const import (
|
||||||
CONF_PASSWORD, CONF_PORT, CONF_USERNAME)
|
CONF_HOST, CONF_NAME, CONF_PATH, CONF_PASSWORD, CONF_PORT, CONF_USERNAME)
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
|
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
|
||||||
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
|
|
||||||
|
REQUIREMENTS = ['aioftp==0.10.1']
|
||||||
DEPENDENCIES = ['ffmpeg']
|
DEPENDENCIES = ['ffmpeg']
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,12 +40,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass,
|
async def async_setup_platform(
|
||||||
config,
|
hass, config, async_add_devices, discovery_info=None):
|
||||||
async_add_devices,
|
|
||||||
discovery_info=None):
|
|
||||||
"""Set up a Yi Camera."""
|
"""Set up a Yi Camera."""
|
||||||
_LOGGER.debug('Received configuration: %s', config)
|
|
||||||
async_add_devices([YiCamera(hass, config)], True)
|
async_add_devices([YiCamera(hass, config)], True)
|
||||||
|
|
||||||
|
|
||||||
@ -54,71 +53,81 @@ class YiCamera(Camera):
|
|||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._extra_arguments = config.get(CONF_FFMPEG_ARGUMENTS)
|
self._extra_arguments = config.get(CONF_FFMPEG_ARGUMENTS)
|
||||||
|
self._ftp = None
|
||||||
self._last_image = None
|
self._last_image = None
|
||||||
self._last_url = None
|
self._last_url = None
|
||||||
self._manager = hass.data[DATA_FFMPEG]
|
self._manager = hass.data[DATA_FFMPEG]
|
||||||
self._name = config.get(CONF_NAME)
|
self._name = config[CONF_NAME]
|
||||||
self.host = config.get(CONF_HOST)
|
self.host = config[CONF_HOST]
|
||||||
self.port = config.get(CONF_PORT)
|
self.port = config[CONF_PORT]
|
||||||
self.path = config.get(CONF_PATH)
|
self.path = config[CONF_PATH]
|
||||||
self.user = config.get(CONF_USERNAME)
|
self.user = config[CONF_USERNAME]
|
||||||
self.passwd = config.get(CONF_PASSWORD)
|
self.passwd = config[CONF_PASSWORD]
|
||||||
|
|
||||||
@property
|
hass.async_add_job(self._connect_to_client)
|
||||||
def name(self):
|
|
||||||
"""Return the name of this camera."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brand(self):
|
def brand(self):
|
||||||
"""Camera brand."""
|
"""Camera brand."""
|
||||||
return DEFAULT_BRAND
|
return DEFAULT_BRAND
|
||||||
|
|
||||||
def get_latest_video_url(self):
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of this camera."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
async def _connect_to_client(self):
|
||||||
|
"""Attempt to establish a connection via FTP."""
|
||||||
|
from aioftp import Client, StatusCodeError
|
||||||
|
|
||||||
|
ftp = Client()
|
||||||
|
try:
|
||||||
|
await ftp.connect(self.host)
|
||||||
|
await ftp.login(self.user, self.passwd)
|
||||||
|
self._ftp = ftp
|
||||||
|
except StatusCodeError as err:
|
||||||
|
raise PlatformNotReady(err)
|
||||||
|
|
||||||
|
async def _get_latest_video_url(self):
|
||||||
"""Retrieve the latest video file from the customized Yi FTP server."""
|
"""Retrieve the latest video file from the customized Yi FTP server."""
|
||||||
from ftplib import FTP, error_perm
|
from aioftp import StatusCodeError
|
||||||
|
|
||||||
ftp = FTP(self.host)
|
|
||||||
try:
|
|
||||||
ftp.login(self.user, self.passwd)
|
|
||||||
except error_perm as exc:
|
|
||||||
_LOGGER.error('There was an error while logging into the camera')
|
|
||||||
_LOGGER.debug(exc)
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ftp.cwd(self.path)
|
await self._ftp.change_directory(self.path)
|
||||||
except error_perm as exc:
|
dirs = []
|
||||||
_LOGGER.error('Unable to find path: %s', self.path)
|
for path, attrs in await self._ftp.list():
|
||||||
_LOGGER.debug(exc)
|
if attrs['type'] == 'dir' and '.' not in str(path):
|
||||||
return False
|
dirs.append(path)
|
||||||
|
|
||||||
dirs = [d for d in ftp.nlst() if '.' not in d]
|
|
||||||
if not dirs:
|
|
||||||
_LOGGER.warning("There don't appear to be any uploaded videos")
|
|
||||||
return False
|
|
||||||
|
|
||||||
latest_dir = dirs[-1]
|
latest_dir = dirs[-1]
|
||||||
ftp.cwd(latest_dir)
|
await self._ftp.change_directory(latest_dir)
|
||||||
videos = ftp.nlst()
|
|
||||||
|
videos = []
|
||||||
|
for path, _ in await self._ftp.list():
|
||||||
|
videos.append(path)
|
||||||
if not videos:
|
if not videos:
|
||||||
_LOGGER.info('Video folder "%s" is empty; delaying', latest_dir)
|
_LOGGER.info('Video folder "%s" empty; delaying', latest_dir)
|
||||||
return False
|
return None
|
||||||
|
|
||||||
return 'ftp://{0}:{1}@{2}:{3}{4}/{5}/{6}'.format(
|
return 'ftp://{0}:{1}@{2}:{3}{4}/{5}/{6}'.format(
|
||||||
self.user, self.passwd, self.host, self.port, self.path,
|
self.user, self.passwd, self.host, self.port, self.path,
|
||||||
latest_dir, videos[-1])
|
latest_dir, videos[-1])
|
||||||
|
except (ConnectionRefusedError, StatusCodeError) as err:
|
||||||
|
_LOGGER.error('Error while fetching video: %s', err)
|
||||||
|
return None
|
||||||
|
|
||||||
async def async_camera_image(self):
|
async def async_camera_image(self):
|
||||||
"""Return a still image response from the camera."""
|
"""Return a still image response from the camera."""
|
||||||
from haffmpeg import ImageFrame, IMAGE_JPEG
|
from haffmpeg import ImageFrame, IMAGE_JPEG
|
||||||
|
|
||||||
url = await self.hass.async_add_job(self.get_latest_video_url)
|
url = await self._get_latest_video_url()
|
||||||
if url != self._last_url:
|
if url != self._last_url:
|
||||||
ffmpeg = ImageFrame(self._manager.binary, loop=self.hass.loop)
|
ffmpeg = ImageFrame(self._manager.binary, loop=self.hass.loop)
|
||||||
self._last_image = await asyncio.shield(ffmpeg.get_image(
|
self._last_image = await asyncio.shield(
|
||||||
url, output_format=IMAGE_JPEG,
|
ffmpeg.get_image(
|
||||||
extra_cmd=self._extra_arguments), loop=self.hass.loop)
|
url,
|
||||||
|
output_format=IMAGE_JPEG,
|
||||||
|
extra_cmd=self._extra_arguments),
|
||||||
|
loop=self.hass.loop)
|
||||||
self._last_url = url
|
self._last_url = url
|
||||||
|
|
||||||
return self._last_image
|
return self._last_image
|
||||||
|
@ -84,6 +84,9 @@ aiodns==1.1.1
|
|||||||
# homeassistant.components.device_tracker.freebox
|
# homeassistant.components.device_tracker.freebox
|
||||||
aiofreepybox==0.0.3
|
aiofreepybox==0.0.3
|
||||||
|
|
||||||
|
# homeassistant.components.camera.yi
|
||||||
|
aioftp==0.10.1
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
aiohttp_cors==0.7.0
|
aiohttp_cors==0.7.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user