-
-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Add reboot command to onvif camera component #29069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d4a0d14
3df2d32
c426fa7
b0d9567
d3fdbff
e40d1e7
9413fe6
56d84ba
e03a590
55fea6d
89ddeda
f35a1d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,8 +18,13 @@ | |
| from zeep.exceptions import Fault | ||
|
|
||
| from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_STREAM, Camera | ||
| from homeassistant.components.camera.const import DOMAIN | ||
| from homeassistant.components.ffmpeg import CONF_EXTRA_ARGUMENTS, DATA_FFMPEG | ||
| from homeassistant.exceptions import PlatformNotReady | ||
| from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream | ||
| import homeassistant.helpers.config_validation as cv | ||
| from homeassistant.helpers.service import async_extract_entity_ids | ||
| import homeassistant.util.dt as dt_util | ||
|
|
||
| from homeassistant.const import ( | ||
| ATTR_ENTITY_ID, | ||
| CONF_HOST, | ||
|
|
@@ -28,39 +33,33 @@ | |
| CONF_PORT, | ||
| CONF_USERNAME, | ||
| ) | ||
| from homeassistant.exceptions import PlatformNotReady | ||
| from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream | ||
| import homeassistant.helpers.config_validation as cv | ||
| from homeassistant.helpers.service import async_extract_entity_ids | ||
| import homeassistant.util.dt as dt_util | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| DEFAULT_NAME = "ONVIF Camera" | ||
| DEFAULT_PORT = 5000 | ||
| DEFAULT_USERNAME = "admin" | ||
| DEFAULT_PASSWORD = "888888" | ||
| DEFAULT_ARGUMENTS = "-pred 1" | ||
| DEFAULT_PROFILE = 0 | ||
|
|
||
| CONF_PROFILE = "profile" | ||
|
|
||
| ATTR_PAN = "pan" | ||
| ATTR_TILT = "tilt" | ||
| ATTR_ZOOM = "zoom" | ||
|
|
||
| DIR_UP = "UP" | ||
| DIR_DOWN = "DOWN" | ||
| DIR_LEFT = "LEFT" | ||
| DIR_RIGHT = "RIGHT" | ||
| ZOOM_OUT = "ZOOM_OUT" | ||
| ZOOM_IN = "ZOOM_IN" | ||
| PTZ_NONE = "NONE" | ||
|
|
||
| SERVICE_PTZ = "onvif_ptz" | ||
| from .const import ( | ||
| ATTR_PAN, | ||
| ATTR_TILT, | ||
| ATTR_ZOOM, | ||
| CONF_PROFILE, | ||
| DEFAULT_ARGUMENTS, | ||
| DEFAULT_NAME, | ||
| DEFAULT_PASSWORD, | ||
| DEFAULT_PORT, | ||
| DEFAULT_PROFILE, | ||
| DEFAULT_USERNAME, | ||
| DIR_DOWN, | ||
| DIR_LEFT, | ||
| DIR_RIGHT, | ||
| DIR_UP, | ||
| DOMAIN, | ||
| ENTITIES, | ||
| ONVIF_DATA, | ||
| PTZ_NONE, | ||
| SERVICE_PTZ, | ||
| SERVICE_REBOOT, | ||
| ZOOM_IN, | ||
| ZOOM_OUT, | ||
| ) | ||
|
|
||
| ONVIF_DATA = "onvif" | ||
| ENTITIES = "entities" | ||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( | ||
| { | ||
|
|
@@ -85,6 +84,8 @@ | |
| } | ||
| ) | ||
|
|
||
| SERVICE_REBOOT_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids}) | ||
|
|
||
|
|
||
| async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): | ||
| """Set up a ONVIF camera.""" | ||
|
|
@@ -111,6 +112,24 @@ async def async_handle_ptz(service): | |
| DOMAIN, SERVICE_PTZ, async_handle_ptz, schema=SERVICE_PTZ_SCHEMA | ||
| ) | ||
|
|
||
| async def async_handle_reboot(service): | ||
| """Handle PTZ service call.""" | ||
| all_cameras = hass.data[ONVIF_DATA][ENTITIES] | ||
| entity_ids = await async_extract_entity_ids(hass, service) | ||
| target_cameras = [] | ||
| if not entity_ids: | ||
| target_cameras = all_cameras | ||
| else: | ||
| target_cameras = [ | ||
| camera for camera in all_cameras if camera.entity_id in entity_ids | ||
| ] | ||
| for camera in target_cameras: | ||
| await camera.async_perform_reboot() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we speed this up by awaiting all camera calls concurrently, eg by using
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. possible i guess, but fairly unlikely if you ask me. To be honest: I'd improve it but don't know how
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Awaiting https://docs.python.org/3/library/asyncio-task.html#asyncio.gather Awaiting tasks in loops, like the for loop here, should be avoided if the task order doesn't matter and there's not a problem with executing the tasks "at the same time". But some devices or APIs can't handle this so in those cases it's ok to keep awaiting in the loop. |
||
|
|
||
| hass.services.async_register( | ||
| DOMAIN, SERVICE_REBOOT, async_handle_reboot, schema=SERVICE_REBOOT_SCHEMA | ||
| ) | ||
|
|
||
| _LOGGER.debug("Constructing the ONVIFHassCamera") | ||
|
|
||
| hass_camera = ONVIFHassCamera(hass, config) | ||
|
|
@@ -278,10 +297,6 @@ async def async_obtain_input_uri(self): | |
|
|
||
| _LOGGER.debug("Retrieving stream uri") | ||
|
|
||
| # Fix Onvif setup error on Goke GK7102 based IP camera | ||
| # where we need to recreate media_service #26781 | ||
| media_service = self._camera.create_media_service() | ||
|
|
||
| req = media_service.create_type("GetStreamUri") | ||
| req.ProfileToken = profiles[self._profile_index].token | ||
| req.StreamSetup = { | ||
|
|
@@ -345,6 +360,20 @@ async def async_perform_ptz(self, pan, tilt, zoom): | |
| else: | ||
| _LOGGER.debug("Camera '%s' doesn't support PTZ.", self._name) | ||
|
|
||
| async def async_perform_reboot(self): | ||
| """Perform a SystemReboot action on the camera.""" | ||
| try: | ||
| _LOGGER.debug("Calling SystemReboot") | ||
| ret = await self._camera.devicemgmt.SystemReboot() | ||
| _LOGGER.debug("Camera '%s' Reboot command returned '%s'", self._name, ret) | ||
| except exceptions.ONVIFError as err: | ||
| _LOGGER.error( | ||
| "Couldn't reboot the camera '%s', please verify " | ||
| "that the camera supports the command. Error: %s", | ||
| self._name, | ||
| err, | ||
| ) | ||
|
|
||
| async def async_added_to_hass(self): | ||
| """Handle entity addition to hass.""" | ||
| _LOGGER.debug("Camera '%s' added to hass", self._name) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| """Constants for the ONVIF Camera component.""" | ||
| DOMAIN = "onvif" | ||
|
|
||
| DEFAULT_NAME = "ONVIF Camera" | ||
| DEFAULT_PORT = 5000 | ||
| DEFAULT_USERNAME = "admin" | ||
| DEFAULT_PASSWORD = "888888" | ||
| DEFAULT_ARGUMENTS = "-pred 1" | ||
| DEFAULT_PROFILE = 0 | ||
|
|
||
| CONF_PROFILE = "profile" | ||
|
|
||
| ATTR_PAN = "pan" | ||
| ATTR_TILT = "tilt" | ||
| ATTR_ZOOM = "zoom" | ||
|
|
||
| DIR_UP = "UP" | ||
| DIR_DOWN = "DOWN" | ||
| DIR_LEFT = "LEFT" | ||
| DIR_RIGHT = "RIGHT" | ||
| ZOOM_OUT = "ZOOM_OUT" | ||
| ZOOM_IN = "ZOOM_IN" | ||
| PTZ_NONE = "NONE" | ||
|
|
||
| SERVICE_PTZ = "ptz" | ||
| SERVICE_REBOOT = "reboot" | ||
|
|
||
| ONVIF_DATA = "onvif" | ||
| ENTITIES = "entities" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are dropping this logic for all other integrations in #29178. Let's not use it here.