Example #1
0
def _get_ezviz_client_instance(entry: ConfigEntry) -> EzvizClient:
    """Initialize a new instance of EzvizClientApi."""
    ezviz_client = EzvizClient(
        entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], entry.data[CONF_REGION]
    )
    # , entry.options.get(CONF_TIMEOUT, DEFAULT_TIMEOUT)
    ezviz_client.login()
    return ezviz_client
Example #2
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Ezviz IP Cameras."""

    conf_cameras = config[CONF_CAMERAS]

    account = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]

    try:
        ezviz_client = EzvizClient(account, password)
        ezviz_client.login()
        cameras = ezviz_client.load_cameras()

    except PyEzvizError as exp:
        _LOGGER.error(exp)
        return

    # now, let's build the HASS devices
    camera_entities = []

    # Add the cameras as devices in HASS
    for camera in cameras:

        camera_username = DEFAULT_CAMERA_USERNAME
        camera_password = ""
        camera_rtsp_stream = ""
        camera_serial = camera["serial"]

        # There seem to be a bug related to localRtspPort in Ezviz API...
        local_rtsp_port = DEFAULT_RTSP_PORT
        if camera["local_rtsp_port"] and camera["local_rtsp_port"] != 0:
            local_rtsp_port = camera["local_rtsp_port"]

        if camera_serial in conf_cameras:
            camera_username = conf_cameras[camera_serial][CONF_USERNAME]
            camera_password = conf_cameras[camera_serial][CONF_PASSWORD]
            camera_rtsp_stream = f"rtsp://{camera_username}:{camera_password}@{camera['local_ip']}:{local_rtsp_port}"
            _LOGGER.debug("Camera %s source stream: %s", camera["serial"],
                          camera_rtsp_stream)

        else:
            _LOGGER.info(
                "Found camera with serial %s without configuration. Add it to configuration.yaml to see the camera stream",
                camera_serial,
            )

        camera["username"] = camera_username
        camera["password"] = camera_password
        camera["rtsp_stream"] = camera_rtsp_stream

        camera["ezviz_camera"] = EzvizCamera(ezviz_client, camera_serial)

        camera_entities.append(HassEzvizCamera(**camera))

    add_entities(camera_entities)
Example #3
0
def _get_ezviz_client_instance(data):
    """Initialize a new instance of EzvizClientApi."""

    ezviz_client = EzvizClient(
        data[CONF_USERNAME],
        data[CONF_PASSWORD],
        data.get(CONF_URL, EU_URL),
        data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
    )

    ezviz_client.login()
    return ezviz_client
Example #4
0
async def _get_ezviz_client_instance(hass: HomeAssistant,
                                     entry: ConfigEntry) -> EzvizClient:
    """Initialize a new instance of EzvizClientApi with username and password."""
    ezviz_client = EzvizClient(
        entry.data[CONF_USERNAME],
        entry.data[CONF_PASSWORD],
        entry.data[CONF_URL],
        entry.options.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
    )

    _token = await hass.async_add_executor_job(ezviz_client.login)

    if _token:
        _LOGGER.info("Updating Ezviz Login token")

        hass.config_entries.async_update_entry(
            entry,
            data={
                CONF_URL: entry.data[CONF_URL],
                CONF_SESSION_ID: _token[CONF_SESSION_ID],
                CONF_RFSESSION_ID: _token[CONF_RFSESSION_ID],
                CONF_TYPE: ATTR_TYPE_CLOUD,
            },
        )

    return ezviz_client
Example #5
0
def _validate_and_create_auth(data: dict) -> dict[str, Any]:
    """Try to login to ezviz cloud account and return token."""
    # Verify cloud credentials by attempting a login request with username and password.
    # Return login token.

    ezviz_client = EzvizClient(
        data[CONF_USERNAME],
        data[CONF_PASSWORD],
        data[CONF_URL],
        data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
    )

    ezviz_token = ezviz_client.login()

    auth_data = {
        CONF_SESSION_ID: ezviz_token[CONF_SESSION_ID],
        CONF_RFSESSION_ID: ezviz_token[CONF_RFSESSION_ID],
        CONF_URL: ezviz_token["api_url"],
        CONF_TYPE: ATTR_TYPE_CLOUD,
    }

    return auth_data
Example #6
0
def validate_input(hass: HomeAssistantType, data: dict) -> Dict[str, Any]:
    """Validate the user input allows us to connect.

    Data has the keys from DATA_SCHEMA with values provided by the user.
    """
    # constructor does login call
    EzvizClient(
        data[CONF_USERNAME],
        data[CONF_PASSWORD],
        data[CONF_REGION],
        data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
    )

    return True
Example #7
0
    async def _validate_and_create_camera_rtsp(self, data: dict) -> FlowResult:
        """Try DESCRIBE on RTSP camera with credentials."""

        # Get Ezviz cloud credentials from config entry
        ezviz_token = {
            CONF_SESSION_ID: None,
            CONF_RFSESSION_ID: None,
            "api_url": None,
        }
        ezviz_timeout = DEFAULT_TIMEOUT

        for item in self._async_current_entries():
            if item.data.get(CONF_TYPE) == ATTR_TYPE_CLOUD:
                ezviz_token = {
                    CONF_SESSION_ID: item.data.get(CONF_SESSION_ID),
                    CONF_RFSESSION_ID: item.data.get(CONF_RFSESSION_ID),
                    "api_url": item.data.get(CONF_URL),
                }
                ezviz_timeout = item.data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT)

        # Abort flow if user removed cloud account before adding camera.
        if ezviz_token.get(CONF_SESSION_ID) is None:
            return self.async_abort(reason="ezviz_cloud_account_missing")

        ezviz_client = EzvizClient(token=ezviz_token, timeout=ezviz_timeout)

        # We need to wake hibernating cameras.
        # First create EZVIZ API instance.
        await self.hass.async_add_executor_job(ezviz_client.login)

        # Secondly try to wake hybernating camera.
        await self.hass.async_add_executor_job(
            ezviz_client.get_detection_sensibility, data[ATTR_SERIAL])

        # Thirdly attempts an authenticated RTSP DESCRIBE request.
        await self.hass.async_add_executor_job(_test_camera_rtsp_creds, data)

        return self.async_create_entry(
            title=data[ATTR_SERIAL],
            data={
                CONF_USERNAME: data[CONF_USERNAME],
                CONF_PASSWORD: data[CONF_PASSWORD],
                CONF_TYPE: ATTR_TYPE_CAMERA,
            },
            options=DEFAULT_OPTIONS,
        )
Example #8
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Ezviz from a config entry."""
    hass.data.setdefault(DOMAIN, {})
    sensor_type: str = entry.data[CONF_TYPE]
    ezviz_client = None

    if not entry.options:
        options = {
            CONF_FFMPEG_ARGUMENTS: DEFAULT_FFMPEG_ARGUMENTS,
            CONF_TIMEOUT: DEFAULT_TIMEOUT,
        }

        hass.config_entries.async_update_entry(entry, options=options)

    if PLATFORMS_BY_TYPE[sensor_type]:

        # Get user account token if not present.
        if not entry.data.get(CONF_SESSION_ID):

            try:
                ezviz_client = await _get_ezviz_client_instance(hass, entry)

            except (InvalidURL, HTTPError, PyEzvizError) as error:
                _LOGGER.error("Unable to connect to Ezviz service: %s",
                              str(error))
                raise ConfigEntryNotReady from error

        if not ezviz_client:
            # No Ezviz login session, call api login().

            ezviz_client = EzvizClient(
                token={
                    CONF_SESSION_ID: entry.data.get(CONF_SESSION_ID),
                    CONF_RFSESSION_ID: entry.data.get(CONF_RFSESSION_ID),
                    "api_url": entry.data.get(CONF_URL),
                },
                timeout=entry.options.get(CONF_TIMEOUT, DEFAULT_TIMEOUT),
            )

            try:
                await hass.async_add_executor_job(ezviz_client.login)

            except (EzvizAuthTokenExpired, EzvizAuthVerificationCode) as error:
                raise ConfigEntryAuthFailed from error

            except (InvalidURL, HTTPError, PyEzvizError) as error:
                _LOGGER.error("Unable to connect to Ezviz service: %s",
                              str(error))
                raise ConfigEntryNotReady from error

        coordinator = EzvizDataUpdateCoordinator(
            hass, api=ezviz_client, api_timeout=entry.options[CONF_TIMEOUT])

        hass.data[DOMAIN][entry.entry_id] = {DATA_COORDINATOR: coordinator}

        await coordinator.async_config_entry_first_refresh()

    entry.async_on_unload(entry.add_update_listener(_async_update_listener))

    if sensor_type == ATTR_TYPE_CAMERA:
        if hass.data.get(DOMAIN):
            for item in hass.config_entries.async_entries(domain=DOMAIN):
                if item.data.get(CONF_TYPE) == ATTR_TYPE_CLOUD:
                    _LOGGER.info("Reload Ezviz main account with camera entry")
                    await hass.config_entries.async_reload(item.entry_id)
                    return True

    hass.config_entries.async_setup_platforms(entry,
                                              PLATFORMS_BY_TYPE[sensor_type])

    return True
Example #9
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Ezviz IP Cameras."""

    conf_cameras = config[ATTR_CAMERAS]

    account = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    region = config[CONF_REGION]

    try:
        ezviz_client = EzvizClient(account, password, region)
        ezviz_client.login()
        cameras = ezviz_client.load_cameras()

    except PyEzvizError as exp:
        _LOGGER.error(exp)
        return

    # now, let's build the HASS devices
    camera_entities = []

    # Add the cameras as devices in HASS
    for camera in cameras:

        camera_username = DEFAULT_CAMERA_USERNAME
        camera_password = ""
        camera_rtsp_stream = ""
        camera_serial = camera["serial"]

        # There seem to be a bug related to localRtspPort in Ezviz API...
        local_rtsp_port = DEFAULT_RTSP_PORT
        if camera["local_rtsp_port"] and camera["local_rtsp_port"] != 0:
            local_rtsp_port = camera["local_rtsp_port"]

        if camera_serial in conf_cameras:
            camera_username = conf_cameras[camera_serial][CONF_USERNAME]
            camera_password = conf_cameras[camera_serial][CONF_PASSWORD]
            camera_rtsp_stream = f"rtsp://{camera_username}:{camera_password}@{camera['local_ip']}:{local_rtsp_port}"
            _LOGGER.debug("Camera %s source stream: %s", camera["serial"],
                          camera_rtsp_stream)

        else:
            _LOGGER.info(
                "Found camera with serial %s without configuration. Add it to configuration.yaml to see the camera stream",
                camera_serial,
            )

        camera["username"] = camera_username
        camera["password"] = camera_password
        camera["rtsp_stream"] = camera_rtsp_stream
        camera["ezviz_client"] = ezviz_client

        camera["ezviz_camera"] = EzvizCamera(ezviz_client, camera_serial)

        camera_entities.append(HassEzvizCamera(hass, **camera))

    add_entities(camera_entities)
    """Setup Services"""
    def ezviz_wake_device(service):
        """Basicaly queries device to wake."""
        ezviz_client.get_detection_sensibility(str(service.data['serial']))

    def ezviz_switch_set(service):
        """Set camera switch service."""
        service_switch = getattr(DeviceSwitchType, service.data[ATTR_SWITCH])

        ezviz_client.switch_status(service.data[ATTR_SERIAL],
                                   service_switch.value,
                                   service.data[ATTR_ENABLE])

    def ezviz_alarm_sound(service):
        """Enable/Disable movement sound alarm."""
        ezviz_client.alarm_sound(str(service.data[ATTR_SERIAL]),
                                 int(service.data['level']), 1)

    def ezviz_set_alarm_detection_sensibility(service):
        """Set camera detection sensibility level service."""
        ezviz_client.detection_sensibility(str(service.data[ATTR_SERIAL]),
                                           int(service.data['level']),
                                           int(service.data['type']))

    def ezviz_ptz(service):
        """Camera PTZ service."""
        ezviz_client.ptzControl(
            str(service.data[ATTR_DIRECTION]).upper(),
            service.data[ATTR_SERIAL], 'START', service.data[ATTR_SPEED])
        ezviz_client.ptzControl(
            str(service.data[ATTR_DIRECTION]).upper(),
            service.data[ATTR_SERIAL], 'STOP', service.data[ATTR_SPEED])

    hass.services.register(DOMAIN, "ezviz_wake_device", ezviz_wake_device)
    hass.services.register(DOMAIN,
                           "ezviz_switch_set",
                           ezviz_switch_set,
                           schema=SERVICE_SET_SWITCH_SCHEMA)
    hass.services.register(DOMAIN, "ezviz_ptz", ezviz_ptz, SERVICE_PTZ_SCHEMA)
    hass.services.register(DOMAIN, "ezviz_alarm_sound", ezviz_alarm_sound)
    hass.services.register(DOMAIN, "ezviz_set_alarm_detection_sensibility",
                           ezviz_set_alarm_detection_sensibility)