mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Axis service vapix call (#7794)
* Initial commit for an Axis service to do Vapix calls to device * Added check to see if metadatastream initiated properly * Make sure to configure the correct IP address when setting up registered devices on system start * Manage reconnection when device is discovered with a different IP * Cleaned up setting new IP * Better naming of event for new IP * New version of dependency axis * Fix flake8 failing * Break out service default strings to constants * Use the dispatcher and not the core event bus for internal communication
This commit is contained in:
parent
6234f2d73f
commit
2a1f8af10a
@ -11,6 +11,7 @@ import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.const import (ATTR_LOCATION, ATTR_TRIPPED,
|
||||
CONF_HOST, CONF_INCLUDE, CONF_NAME,
|
||||
CONF_PASSWORD, CONF_TRIGGER_TIME,
|
||||
@ -18,11 +19,12 @@ from homeassistant.const import (ATTR_LOCATION, ATTR_TRIPPED,
|
||||
from homeassistant.components.discovery import SERVICE_AXIS
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.loader import get_component
|
||||
|
||||
|
||||
REQUIREMENTS = ['axis==7']
|
||||
REQUIREMENTS = ['axis==8']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -59,6 +61,21 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
SERVICE_VAPIX_CALL = 'vapix_call'
|
||||
SERVICE_VAPIX_CALL_RESPONSE = 'vapix_call_response'
|
||||
SERVICE_CGI = 'cgi'
|
||||
SERVICE_ACTION = 'action'
|
||||
SERVICE_PARAM = 'param'
|
||||
SERVICE_DEFAULT_CGI = 'param.cgi'
|
||||
SERVICE_DEFAULT_ACTION = 'update'
|
||||
|
||||
SERVICE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Required(SERVICE_PARAM): cv.string,
|
||||
vol.Optional(SERVICE_CGI, default=SERVICE_DEFAULT_CGI): cv.string,
|
||||
vol.Optional(SERVICE_ACTION, default=SERVICE_DEFAULT_ACTION): cv.string,
|
||||
})
|
||||
|
||||
|
||||
def request_configuration(hass, name, host, serialnumber):
|
||||
"""Request configuration steps from the user."""
|
||||
@ -135,23 +152,34 @@ def setup(hass, base_config):
|
||||
|
||||
def axis_device_discovered(service, discovery_info):
|
||||
"""Called when axis devices has been found."""
|
||||
host = discovery_info['host']
|
||||
host = discovery_info[CONF_HOST]
|
||||
name = discovery_info['hostname']
|
||||
serialnumber = discovery_info['properties']['macaddress']
|
||||
|
||||
if serialnumber not in AXIS_DEVICES:
|
||||
config_file = _read_config(hass)
|
||||
if serialnumber in config_file:
|
||||
# Device config saved to file
|
||||
try:
|
||||
config = DEVICE_SCHEMA(config_file[serialnumber])
|
||||
config[CONF_HOST] = host
|
||||
except vol.Invalid as err:
|
||||
_LOGGER.error("Bad data from %s. %s", CONFIG_FILE, err)
|
||||
return False
|
||||
if not setup_device(hass, config):
|
||||
_LOGGER.error("Couldn\'t set up %s", config['name'])
|
||||
_LOGGER.error("Couldn\'t set up %s", config[CONF_NAME])
|
||||
else:
|
||||
# New device, create configuration request for UI
|
||||
request_configuration(hass, name, host, serialnumber)
|
||||
else:
|
||||
# Device already registered, but on a different IP
|
||||
device = AXIS_DEVICES[serialnumber]
|
||||
device.url = host
|
||||
async_dispatcher_send(hass,
|
||||
DOMAIN + '_' + device.name + '_new_ip',
|
||||
host)
|
||||
|
||||
# Register discovery service
|
||||
discovery.listen(hass, SERVICE_AXIS, axis_device_discovered)
|
||||
|
||||
if DOMAIN in base_config:
|
||||
@ -160,7 +188,30 @@ def setup(hass, base_config):
|
||||
if CONF_NAME not in config:
|
||||
config[CONF_NAME] = device
|
||||
if not setup_device(hass, config):
|
||||
_LOGGER.error("Couldn\'t set up %s", config['name'])
|
||||
_LOGGER.error("Couldn\'t set up %s", config[CONF_NAME])
|
||||
|
||||
# Services to communicate with device.
|
||||
descriptions = load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
|
||||
def vapix_service(call):
|
||||
"""Service to send a message."""
|
||||
for _, device in AXIS_DEVICES.items():
|
||||
if device.name == call.data[CONF_NAME]:
|
||||
response = device.do_request(call.data[SERVICE_CGI],
|
||||
call.data[SERVICE_ACTION],
|
||||
call.data[SERVICE_PARAM])
|
||||
hass.bus.async_fire(SERVICE_VAPIX_CALL_RESPONSE, response)
|
||||
return True
|
||||
_LOGGER.info("Couldn\'t find device %s", call.data[CONF_NAME])
|
||||
return False
|
||||
|
||||
# Register service with Home Assistant.
|
||||
hass.services.register(DOMAIN,
|
||||
SERVICE_VAPIX_CALL,
|
||||
vapix_service,
|
||||
descriptions[DOMAIN][SERVICE_VAPIX_CALL],
|
||||
schema=SERVICE_SCHEMA)
|
||||
|
||||
return True
|
||||
|
||||
@ -190,8 +241,16 @@ def setup_device(hass, config):
|
||||
|
||||
if enable_metadatastream:
|
||||
device.initialize_new_event = event_initialized
|
||||
device.initiate_metadatastream()
|
||||
if not device.initiate_metadatastream():
|
||||
notification = get_component('persistent_notification')
|
||||
notification.create(hass,
|
||||
'Dependency missing for sensors, '
|
||||
'please check documentation',
|
||||
title=DOMAIN,
|
||||
notification_id='axis_notification')
|
||||
|
||||
AXIS_DEVICES[device.serial_number] = device
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -311,4 +370,4 @@ REMAP = [{'type': 'motion',
|
||||
'class': 'input',
|
||||
'topic': 'tns1:Device/tnsaxis:IO/Port',
|
||||
'subscribe': 'onvif:Device/axis:IO/Port',
|
||||
'platform': 'sensor'}, ]
|
||||
'platform': 'binary_sensor'}, ]
|
||||
|
@ -7,15 +7,16 @@ https://home-assistant.io/components/camera.axis/
|
||||
import logging
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
|
||||
CONF_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION)
|
||||
from homeassistant.components.camera.mjpeg import (
|
||||
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['axis']
|
||||
DOMAIN = 'axis'
|
||||
DEPENDENCIES = [DOMAIN]
|
||||
|
||||
|
||||
def _get_image_url(host, mode):
|
||||
@ -27,12 +28,29 @@ def _get_image_url(host, mode):
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Setup Axis camera."""
|
||||
device_info = {
|
||||
CONF_NAME: discovery_info['name'],
|
||||
CONF_USERNAME: discovery_info['username'],
|
||||
CONF_PASSWORD: discovery_info['password'],
|
||||
CONF_MJPEG_URL: _get_image_url(discovery_info['host'], 'mjpeg'),
|
||||
CONF_STILL_IMAGE_URL: _get_image_url(discovery_info['host'], 'single'),
|
||||
config = {
|
||||
CONF_NAME: discovery_info[CONF_NAME],
|
||||
CONF_USERNAME: discovery_info[CONF_USERNAME],
|
||||
CONF_PASSWORD: discovery_info[CONF_PASSWORD],
|
||||
CONF_MJPEG_URL: _get_image_url(discovery_info[CONF_HOST], 'mjpeg'),
|
||||
CONF_STILL_IMAGE_URL: _get_image_url(discovery_info[CONF_HOST],
|
||||
'single'),
|
||||
CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION,
|
||||
}
|
||||
add_devices([MjpegCamera(hass, device_info)])
|
||||
add_devices([AxisCamera(hass, config)])
|
||||
|
||||
|
||||
class AxisCamera(MjpegCamera):
|
||||
"""AxisCamera class."""
|
||||
|
||||
def __init__(self, hass, config):
|
||||
"""Initialize Axis Communications camera component."""
|
||||
super().__init__(hass, config)
|
||||
async_dispatcher_connect(hass,
|
||||
DOMAIN + '_' + config[CONF_NAME] + '_new_ip',
|
||||
self._new_ip)
|
||||
|
||||
def _new_ip(self, host):
|
||||
"""Set new IP for video stream."""
|
||||
self._mjpeg_url = _get_image_url(host, 'mjpeg')
|
||||
self._still_image_url = _get_image_url(host, 'mjpeg')
|
||||
|
@ -453,3 +453,20 @@ eight_sleep:
|
||||
duration:
|
||||
description: Duration to heat at the target level in seconds.
|
||||
example: 3600
|
||||
|
||||
axis:
|
||||
vapix_call:
|
||||
description: Configure device using Vapix parameter management.
|
||||
fields:
|
||||
name:
|
||||
description: Name of device to Configure. [Required]
|
||||
example: M1065-W
|
||||
cgi:
|
||||
description: Which cgi to call on device. [Optional] Default is 'param.cgi'
|
||||
example: 'applications/control.cgi'
|
||||
action:
|
||||
description: What type of call. [Optional] Default is 'update'
|
||||
example: 'start'
|
||||
param:
|
||||
description: What parameter to operate on. [Required]
|
||||
example: 'package=VideoMotionDetection'
|
||||
|
@ -74,7 +74,7 @@ apns2==0.1.1
|
||||
# avion==0.6
|
||||
|
||||
# homeassistant.components.axis
|
||||
axis==7
|
||||
axis==8
|
||||
|
||||
# homeassistant.components.sensor.modem_callerid
|
||||
basicmodem==0.7
|
||||
|
Loading…
x
Reference in New Issue
Block a user