"""Support for Blink Home Camera System.""" from datetime import timedelta import logging from blinkpy import blinkpy import voluptuous as vol from homeassistant.const import ( CONF_BINARY_SENSORS, CONF_FILENAME, CONF_MODE, CONF_MONITORED_CONDITIONS, CONF_NAME, CONF_OFFSET, CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_SENSORS, CONF_USERNAME, TEMP_FAHRENHEIT, ) from homeassistant.helpers import config_validation as cv, discovery _LOGGER = logging.getLogger(__name__) DOMAIN = "blink" BLINK_DATA = "blink" CONF_CAMERA = "camera" CONF_ALARM_CONTROL_PANEL = "alarm_control_panel" DEFAULT_BRAND = "Blink" DEFAULT_ATTRIBUTION = "Data provided by immedia-semi.com" SIGNAL_UPDATE_BLINK = "blink_update" DEFAULT_SCAN_INTERVAL = timedelta(seconds=300) TYPE_CAMERA_ARMED = "motion_enabled" TYPE_MOTION_DETECTED = "motion_detected" TYPE_TEMPERATURE = "temperature" TYPE_BATTERY = "battery" TYPE_WIFI_STRENGTH = "wifi_strength" SERVICE_REFRESH = "blink_update" SERVICE_TRIGGER = "trigger_camera" SERVICE_SAVE_VIDEO = "save_video" BINARY_SENSORS = { TYPE_CAMERA_ARMED: ["Camera Armed", "mdi:verified"], TYPE_MOTION_DETECTED: ["Motion Detected", "mdi:run-fast"], } SENSORS = { TYPE_TEMPERATURE: ["Temperature", TEMP_FAHRENHEIT, "mdi:thermometer"], TYPE_BATTERY: ["Battery", "", "mdi:battery-80"], TYPE_WIFI_STRENGTH: ["Wifi Signal", "dBm", "mdi:wifi-strength-2"], } BINARY_SENSOR_SCHEMA = vol.Schema( { vol.Optional(CONF_MONITORED_CONDITIONS, default=list(BINARY_SENSORS)): vol.All( cv.ensure_list, [vol.In(BINARY_SENSORS)] ) } ) SENSOR_SCHEMA = vol.Schema( { vol.Optional(CONF_MONITORED_CONDITIONS, default=list(SENSORS)): vol.All( cv.ensure_list, [vol.In(SENSORS)] ) } ) SERVICE_TRIGGER_SCHEMA = vol.Schema({vol.Required(CONF_NAME): cv.string}) SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema( {vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILENAME): cv.string} ) CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Optional( CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL ): cv.time_period, vol.Optional(CONF_BINARY_SENSORS, default={}): BINARY_SENSOR_SCHEMA, vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA, vol.Optional(CONF_OFFSET, default=1): int, vol.Optional(CONF_MODE, default=""): cv.string, } ) }, extra=vol.ALLOW_EXTRA, ) def setup(hass, config): """Set up Blink System.""" conf = config[BLINK_DATA] username = conf[CONF_USERNAME] password = conf[CONF_PASSWORD] scan_interval = conf[CONF_SCAN_INTERVAL] is_legacy = bool(conf[CONF_MODE] == "legacy") motion_interval = conf[CONF_OFFSET] hass.data[BLINK_DATA] = blinkpy.Blink( username=username, password=password, motion_interval=motion_interval, legacy_subdomain=is_legacy, ) hass.data[BLINK_DATA].refresh_rate = scan_interval.total_seconds() hass.data[BLINK_DATA].start() platforms = [ ("alarm_control_panel", {}), ("binary_sensor", conf[CONF_BINARY_SENSORS]), ("camera", {}), ("sensor", conf[CONF_SENSORS]), ] for component, schema in platforms: discovery.load_platform(hass, component, DOMAIN, schema, config) def trigger_camera(call): """Trigger a camera.""" cameras = hass.data[BLINK_DATA].cameras name = call.data[CONF_NAME] if name in cameras: cameras[name].snap_picture() hass.data[BLINK_DATA].refresh(force_cache=True) def blink_refresh(event_time): """Call blink to refresh info.""" hass.data[BLINK_DATA].refresh(force_cache=True) async def async_save_video(call): """Call save video service handler.""" await async_handle_save_video_service(hass, call) hass.services.register(DOMAIN, SERVICE_REFRESH, blink_refresh) hass.services.register( DOMAIN, SERVICE_TRIGGER, trigger_camera, schema=SERVICE_TRIGGER_SCHEMA ) hass.services.register( DOMAIN, SERVICE_SAVE_VIDEO, async_save_video, schema=SERVICE_SAVE_VIDEO_SCHEMA ) return True async def async_handle_save_video_service(hass, call): """Handle save video service calls.""" camera_name = call.data[CONF_NAME] video_path = call.data[CONF_FILENAME] if not hass.config.is_allowed_path(video_path): _LOGGER.error("Can't write %s, no access to path!", video_path) return def _write_video(camera_name, video_path): """Call video write.""" all_cameras = hass.data[BLINK_DATA].cameras if camera_name in all_cameras: all_cameras[camera_name].video_to_file(video_path) try: await hass.async_add_executor_job(_write_video, camera_name, video_path) except OSError as err: _LOGGER.error("Can't write image to file: %s", err)