171 lines
5.0 KiB
Python
171 lines
5.0 KiB
Python
"""Support for Blink Home Camera System."""
|
|
import logging
|
|
from datetime import timedelta
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.helpers import config_validation as cv, discovery
|
|
from homeassistant.const import (
|
|
CONF_USERNAME,
|
|
CONF_PASSWORD,
|
|
CONF_NAME,
|
|
CONF_SCAN_INTERVAL,
|
|
CONF_BINARY_SENSORS,
|
|
CONF_SENSORS,
|
|
CONF_FILENAME,
|
|
CONF_MONITORED_CONDITIONS,
|
|
CONF_MODE,
|
|
CONF_OFFSET,
|
|
TEMP_FAHRENHEIT,
|
|
)
|
|
|
|
_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."""
|
|
from blinkpy import blinkpy
|
|
|
|
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)
|