mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Solve Recorder component failing when using Axis component (#9293)
* Bump Axis requirement to v10 Fix issues related to non JSON serializable items and recorder component (8297) Add support to configure HTTP port (8403) * Changed local port definition to CONF_PORT * On request config is now sent to the camera platform as well, and in order better explain what is what the old internal config is now device_config and hass own config is the only one referenced as config * Missed to add device_config to setup in discovered device * Bump to V12 that has got a dependency fix * Update requirements_all * Add port configuration to automatically discovered devices Allow setup to pass without Axis being configured in configuration.yaml
This commit is contained in:
parent
8ea7e4bb55
commit
dcaa5fe443
@ -14,7 +14,7 @@ import voluptuous as vol
|
|||||||
from homeassistant.config import load_yaml_config_file
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.const import (ATTR_LOCATION, ATTR_TRIPPED,
|
from homeassistant.const import (ATTR_LOCATION, ATTR_TRIPPED,
|
||||||
CONF_HOST, CONF_INCLUDE, CONF_NAME,
|
CONF_HOST, CONF_INCLUDE, CONF_NAME,
|
||||||
CONF_PASSWORD, CONF_TRIGGER_TIME,
|
CONF_PASSWORD, CONF_PORT, CONF_TRIGGER_TIME,
|
||||||
CONF_USERNAME, EVENT_HOMEASSISTANT_STOP)
|
CONF_USERNAME, EVENT_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.components.discovery import SERVICE_AXIS
|
from homeassistant.components.discovery import SERVICE_AXIS
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
@ -23,7 +23,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
|
|||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
|
||||||
REQUIREMENTS = ['axis==8']
|
REQUIREMENTS = ['axis==12']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -51,6 +51,7 @@ DEVICE_SCHEMA = vol.Schema({
|
|||||||
vol.Optional(CONF_USERNAME, default=AXIS_DEFAULT_USERNAME): cv.string,
|
vol.Optional(CONF_USERNAME, default=AXIS_DEFAULT_USERNAME): cv.string,
|
||||||
vol.Optional(CONF_PASSWORD, default=AXIS_DEFAULT_PASSWORD): cv.string,
|
vol.Optional(CONF_PASSWORD, default=AXIS_DEFAULT_PASSWORD): cv.string,
|
||||||
vol.Optional(CONF_TRIGGER_TIME, default=0): cv.positive_int,
|
vol.Optional(CONF_TRIGGER_TIME, default=0): cv.positive_int,
|
||||||
|
vol.Optional(CONF_PORT, default=80): cv.positive_int,
|
||||||
vol.Optional(ATTR_LOCATION, default=''): cv.string,
|
vol.Optional(ATTR_LOCATION, default=''): cv.string,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ SERVICE_SCHEMA = vol.Schema({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def request_configuration(hass, name, host, serialnumber):
|
def request_configuration(hass, config, name, host, serialnumber):
|
||||||
"""Request configuration steps from the user."""
|
"""Request configuration steps from the user."""
|
||||||
configurator = hass.components.configurator
|
configurator = hass.components.configurator
|
||||||
|
|
||||||
@ -91,15 +92,15 @@ def request_configuration(hass, name, host, serialnumber):
|
|||||||
if CONF_NAME not in callback_data:
|
if CONF_NAME not in callback_data:
|
||||||
callback_data[CONF_NAME] = name
|
callback_data[CONF_NAME] = name
|
||||||
try:
|
try:
|
||||||
config = DEVICE_SCHEMA(callback_data)
|
device_config = DEVICE_SCHEMA(callback_data)
|
||||||
except vol.Invalid:
|
except vol.Invalid:
|
||||||
configurator.notify_errors(request_id,
|
configurator.notify_errors(request_id,
|
||||||
"Bad input, please check spelling.")
|
"Bad input, please check spelling.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if setup_device(hass, config):
|
if setup_device(hass, config, device_config):
|
||||||
config_file = _read_config(hass)
|
config_file = _read_config(hass)
|
||||||
config_file[serialnumber] = dict(config)
|
config_file[serialnumber] = dict(device_config)
|
||||||
del config_file[serialnumber]['hass']
|
del config_file[serialnumber]['hass']
|
||||||
_write_config(hass, config_file)
|
_write_config(hass, config_file)
|
||||||
configurator.request_done(request_id)
|
configurator.request_done(request_id)
|
||||||
@ -132,6 +133,9 @@ def request_configuration(hass, name, host, serialnumber):
|
|||||||
{'id': ATTR_LOCATION,
|
{'id': ATTR_LOCATION,
|
||||||
'name': "Physical location of device (optional)",
|
'name': "Physical location of device (optional)",
|
||||||
'type': 'text'},
|
'type': 'text'},
|
||||||
|
{'id': CONF_PORT,
|
||||||
|
'name': "HTTP port (default=80)",
|
||||||
|
'type': 'number'},
|
||||||
{'id': CONF_TRIGGER_TIME,
|
{'id': CONF_TRIGGER_TIME,
|
||||||
'name': "Sensor update interval (optional)",
|
'name': "Sensor update interval (optional)",
|
||||||
'type': 'number'},
|
'type': 'number'},
|
||||||
@ -139,7 +143,7 @@ def request_configuration(hass, name, host, serialnumber):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, base_config):
|
def setup(hass, config):
|
||||||
"""Common setup for Axis devices."""
|
"""Common setup for Axis devices."""
|
||||||
def _shutdown(call): # pylint: disable=unused-argument
|
def _shutdown(call): # pylint: disable=unused-argument
|
||||||
"""Stop the metadatastream on shutdown."""
|
"""Stop the metadatastream on shutdown."""
|
||||||
@ -160,16 +164,17 @@ def setup(hass, base_config):
|
|||||||
if serialnumber in config_file:
|
if serialnumber in config_file:
|
||||||
# Device config saved to file
|
# Device config saved to file
|
||||||
try:
|
try:
|
||||||
config = DEVICE_SCHEMA(config_file[serialnumber])
|
device_config = DEVICE_SCHEMA(config_file[serialnumber])
|
||||||
config[CONF_HOST] = host
|
device_config[CONF_HOST] = host
|
||||||
except vol.Invalid as err:
|
except vol.Invalid as err:
|
||||||
_LOGGER.error("Bad data from %s. %s", CONFIG_FILE, err)
|
_LOGGER.error("Bad data from %s. %s", CONFIG_FILE, err)
|
||||||
return False
|
return False
|
||||||
if not setup_device(hass, config):
|
if not setup_device(hass, config, device_config):
|
||||||
_LOGGER.error("Couldn\'t set up %s", config[CONF_NAME])
|
_LOGGER.error("Couldn\'t set up %s",
|
||||||
|
device_config[CONF_NAME])
|
||||||
else:
|
else:
|
||||||
# New device, create configuration request for UI
|
# New device, create configuration request for UI
|
||||||
request_configuration(hass, name, host, serialnumber)
|
request_configuration(hass, config, name, host, serialnumber)
|
||||||
else:
|
else:
|
||||||
# Device already registered, but on a different IP
|
# Device already registered, but on a different IP
|
||||||
device = AXIS_DEVICES[serialnumber]
|
device = AXIS_DEVICES[serialnumber]
|
||||||
@ -181,13 +186,13 @@ def setup(hass, base_config):
|
|||||||
# Register discovery service
|
# Register discovery service
|
||||||
discovery.listen(hass, SERVICE_AXIS, axis_device_discovered)
|
discovery.listen(hass, SERVICE_AXIS, axis_device_discovered)
|
||||||
|
|
||||||
if DOMAIN in base_config:
|
if DOMAIN in config:
|
||||||
for device in base_config[DOMAIN]:
|
for device in config[DOMAIN]:
|
||||||
config = base_config[DOMAIN][device]
|
device_config = config[DOMAIN][device]
|
||||||
if CONF_NAME not in config:
|
if CONF_NAME not in device_config:
|
||||||
config[CONF_NAME] = device
|
device_config[CONF_NAME] = device
|
||||||
if not setup_device(hass, config):
|
if not setup_device(hass, config, device_config):
|
||||||
_LOGGER.error("Couldn\'t set up %s", config[CONF_NAME])
|
_LOGGER.error("Couldn\'t set up %s", device_config[CONF_NAME])
|
||||||
|
|
||||||
# Services to communicate with device.
|
# Services to communicate with device.
|
||||||
descriptions = load_yaml_config_file(
|
descriptions = load_yaml_config_file(
|
||||||
@ -215,20 +220,20 @@ def setup(hass, base_config):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def setup_device(hass, config):
|
def setup_device(hass, config, device_config):
|
||||||
"""Set up device."""
|
"""Set up device."""
|
||||||
from axis import AxisDevice
|
from axis import AxisDevice
|
||||||
|
|
||||||
config['hass'] = hass
|
device_config['hass'] = hass
|
||||||
device = AxisDevice(config) # Initialize device
|
device = AxisDevice(device_config) # Initialize device
|
||||||
enable_metadatastream = False
|
enable_metadatastream = False
|
||||||
|
|
||||||
if device.serial_number is None:
|
if device.serial_number is None:
|
||||||
# If there is no serial number a connection could not be made
|
# If there is no serial number a connection could not be made
|
||||||
_LOGGER.error("Couldn\'t connect to %s", config[CONF_HOST])
|
_LOGGER.error("Couldn\'t connect to %s", device_config[CONF_HOST])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for component in config[CONF_INCLUDE]:
|
for component in device_config[CONF_INCLUDE]:
|
||||||
if component in EVENT_TYPES:
|
if component in EVENT_TYPES:
|
||||||
# Sensors are created by device calling event_initialized
|
# Sensors are created by device calling event_initialized
|
||||||
# when receiving initialize messages on metadatastream
|
# when receiving initialize messages on metadatastream
|
||||||
@ -236,7 +241,18 @@ def setup_device(hass, config):
|
|||||||
if not enable_metadatastream:
|
if not enable_metadatastream:
|
||||||
enable_metadatastream = True
|
enable_metadatastream = True
|
||||||
else:
|
else:
|
||||||
discovery.load_platform(hass, component, DOMAIN, config)
|
camera_config = {
|
||||||
|
CONF_HOST: device_config[CONF_HOST],
|
||||||
|
CONF_NAME: device_config[CONF_NAME],
|
||||||
|
CONF_PORT: device_config[CONF_PORT],
|
||||||
|
CONF_USERNAME: device_config[CONF_USERNAME],
|
||||||
|
CONF_PASSWORD: device_config[CONF_PASSWORD]
|
||||||
|
}
|
||||||
|
discovery.load_platform(hass,
|
||||||
|
component,
|
||||||
|
DOMAIN,
|
||||||
|
camera_config,
|
||||||
|
config)
|
||||||
|
|
||||||
if enable_metadatastream:
|
if enable_metadatastream:
|
||||||
device.initialize_new_event = event_initialized
|
device.initialize_new_event = event_initialized
|
||||||
|
@ -7,7 +7,7 @@ https://home-assistant.io/components/camera.axis/
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD,
|
CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_PORT,
|
||||||
CONF_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION)
|
CONF_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION)
|
||||||
from homeassistant.components.camera.mjpeg import (
|
from homeassistant.components.camera.mjpeg import (
|
||||||
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera)
|
CONF_MJPEG_URL, CONF_STILL_IMAGE_URL, MjpegCamera)
|
||||||
@ -19,38 +19,44 @@ DOMAIN = 'axis'
|
|||||||
DEPENDENCIES = [DOMAIN]
|
DEPENDENCIES = [DOMAIN]
|
||||||
|
|
||||||
|
|
||||||
def _get_image_url(host, mode):
|
def _get_image_url(host, port, mode):
|
||||||
if mode == 'mjpeg':
|
if mode == 'mjpeg':
|
||||||
return 'http://{}/axis-cgi/mjpg/video.cgi'.format(host)
|
return 'http://{}:{}/axis-cgi/mjpg/video.cgi'.format(host, port)
|
||||||
elif mode == 'single':
|
elif mode == 'single':
|
||||||
return 'http://{}/axis-cgi/jpg/image.cgi'.format(host)
|
return 'http://{}:{}/axis-cgi/jpg/image.cgi'.format(host, port)
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||||
"""Setup Axis camera."""
|
"""Setup Axis camera."""
|
||||||
config = {
|
camera_config = {
|
||||||
CONF_NAME: discovery_info[CONF_NAME],
|
CONF_NAME: discovery_info[CONF_NAME],
|
||||||
CONF_USERNAME: discovery_info[CONF_USERNAME],
|
CONF_USERNAME: discovery_info[CONF_USERNAME],
|
||||||
CONF_PASSWORD: discovery_info[CONF_PASSWORD],
|
CONF_PASSWORD: discovery_info[CONF_PASSWORD],
|
||||||
CONF_MJPEG_URL: _get_image_url(discovery_info[CONF_HOST], 'mjpeg'),
|
CONF_MJPEG_URL: _get_image_url(discovery_info[CONF_HOST],
|
||||||
|
str(discovery_info[CONF_PORT]),
|
||||||
|
'mjpeg'),
|
||||||
CONF_STILL_IMAGE_URL: _get_image_url(discovery_info[CONF_HOST],
|
CONF_STILL_IMAGE_URL: _get_image_url(discovery_info[CONF_HOST],
|
||||||
|
str(discovery_info[CONF_PORT]),
|
||||||
'single'),
|
'single'),
|
||||||
CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION,
|
CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION,
|
||||||
}
|
}
|
||||||
add_devices([AxisCamera(hass, config)])
|
add_devices([AxisCamera(hass,
|
||||||
|
camera_config,
|
||||||
|
str(discovery_info[CONF_PORT]))])
|
||||||
|
|
||||||
|
|
||||||
class AxisCamera(MjpegCamera):
|
class AxisCamera(MjpegCamera):
|
||||||
"""AxisCamera class."""
|
"""AxisCamera class."""
|
||||||
|
|
||||||
def __init__(self, hass, config):
|
def __init__(self, hass, config, port):
|
||||||
"""Initialize Axis Communications camera component."""
|
"""Initialize Axis Communications camera component."""
|
||||||
super().__init__(hass, config)
|
super().__init__(hass, config)
|
||||||
|
self.port = port
|
||||||
async_dispatcher_connect(hass,
|
async_dispatcher_connect(hass,
|
||||||
DOMAIN + '_' + config[CONF_NAME] + '_new_ip',
|
DOMAIN + '_' + config[CONF_NAME] + '_new_ip',
|
||||||
self._new_ip)
|
self._new_ip)
|
||||||
|
|
||||||
def _new_ip(self, host):
|
def _new_ip(self, host):
|
||||||
"""Set new IP for video stream."""
|
"""Set new IP for video stream."""
|
||||||
self._mjpeg_url = _get_image_url(host, 'mjpeg')
|
self._mjpeg_url = _get_image_url(host, self.port, 'mjpeg')
|
||||||
self._still_image_url = _get_image_url(host, 'mjpeg')
|
self._still_image_url = _get_image_url(host, self.port, 'single')
|
||||||
|
@ -85,7 +85,7 @@ asterisk_mbox==0.4.0
|
|||||||
# avion==0.7
|
# avion==0.7
|
||||||
|
|
||||||
# homeassistant.components.axis
|
# homeassistant.components.axis
|
||||||
axis==8
|
axis==12
|
||||||
|
|
||||||
# homeassistant.components.sensor.modem_callerid
|
# homeassistant.components.sensor.modem_callerid
|
||||||
basicmodem==0.7
|
basicmodem==0.7
|
||||||
|
Loading…
x
Reference in New Issue
Block a user