Skip to content

Commit

Permalink
Add: Ability to specify custom stream link
Browse files Browse the repository at this point in the history
  • Loading branch information
JurajNyiri committed Dec 2, 2021
1 parent 4dfe0c2 commit f326870
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 8 deletions.
10 changes: 10 additions & 0 deletions custom_components/tapo_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import (
ENABLE_SOUND_DETECTION,
CONF_CUSTOM_STREAM,
LOGGER,
DOMAIN,
ENABLE_MOTION_SENSOR,
Expand Down Expand Up @@ -101,6 +102,15 @@ async def async_migrate_entry(hass, config_entry: ConfigEntry):

config_entry.version = 7

if config_entry.version == 7:

new = {**config_entry.data}
new[CONF_CUSTOM_STREAM] = ""

config_entry.data = {**new}

config_entry.version = 8

LOGGER.info("Migration to version %s successful", config_entry.version)

return True
Expand Down
5 changes: 5 additions & 0 deletions custom_components/tapo_control/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from haffmpeg.camera import CameraMjpeg
from haffmpeg.tools import IMAGE_JPEG, ImageFrame
from .const import (
CONF_CUSTOM_STREAM,
ENABLE_SOUND_DETECTION,
ENABLE_STREAM,
SERVICE_SET_LED_MODE,
Expand Down Expand Up @@ -132,6 +133,7 @@ def __init__(
self._sound_detection_peak = entry.data.get(SOUND_DETECTION_PEAK)
self._sound_detection_duration = entry.data.get(SOUND_DETECTION_DURATION)
self._sound_detection_reset = entry.data.get(SOUND_DETECTION_RESET)
self._custom_stream = entry.data.get(CONF_CUSTOM_STREAM)
self._attributes = tapoData["camData"]["basic_info"]

self.updateCam(tapoData["camData"])
Expand Down Expand Up @@ -253,6 +255,9 @@ async def handle_async_mjpeg_stream(self, request):
await stream.close()

def getStreamSource(self):
if self._custom_stream != "":
return self._custom_stream

if self._hdstream:
streamType = "stream1"
else:
Expand Down
26 changes: 24 additions & 2 deletions custom_components/tapo_control/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
SOUND_DETECTION_DURATION,
SOUND_DETECTION_PEAK,
SOUND_DETECTION_RESET,
CONF_CUSTOM_STREAM,
)


@config_entries.HANDLERS.register(DOMAIN)
class FlowHandler(config_entries.ConfigFlow):
"""Handle a config flow."""

VERSION = 7
VERSION = 8

@staticmethod
def async_get_options_flow(config_entry):
Expand Down Expand Up @@ -75,6 +76,7 @@ async def async_step_other_options(self, user_input=None):
sound_detection_duration = 1
sound_detection_reset = 10
extra_arguments = ""
custom_stream = ""
if user_input is not None:
if ENABLE_MOTION_SENSOR in user_input:
enable_motion_sensor = user_input[ENABLE_MOTION_SENSOR]
Expand All @@ -96,6 +98,10 @@ async def async_step_other_options(self, user_input=None):
sound_detection_peak = user_input[SOUND_DETECTION_PEAK]
else:
sound_detection_peak = -50
if CONF_CUSTOM_STREAM in user_input:
custom_stream = user_input[CONF_CUSTOM_STREAM]
else:
custom_stream = ""
if SOUND_DETECTION_DURATION in user_input:
sound_detection_duration = user_input[SOUND_DETECTION_DURATION]
else:
Expand Down Expand Up @@ -127,6 +133,7 @@ async def async_step_other_options(self, user_input=None):
SOUND_DETECTION_DURATION: sound_detection_duration,
SOUND_DETECTION_RESET: sound_detection_reset,
CONF_EXTRA_ARGUMENTS: extra_arguments,
CONF_CUSTOM_STREAM: custom_stream,
},
)

Expand Down Expand Up @@ -165,6 +172,10 @@ async def async_step_other_options(self, user_input=None):
CONF_EXTRA_ARGUMENTS,
description={"suggested_value": extra_arguments},
): str,
vol.Optional(
CONF_CUSTOM_STREAM,
description={"suggested_value": custom_stream},
): str,
}
),
errors=errors,
Expand Down Expand Up @@ -340,6 +351,7 @@ async def async_step_auth(self, user_input=None):
sound_detection_duration = self.config_entry.data[SOUND_DETECTION_DURATION]
sound_detection_reset = self.config_entry.data[SOUND_DETECTION_RESET]
extra_arguments = self.config_entry.data[CONF_EXTRA_ARGUMENTS]
custom_stream = self.config_entry.data[CONF_CUSTOM_STREAM]
if user_input is not None:
try:
host = self.config_entry.data[CONF_IP_ADDRESS]
Expand Down Expand Up @@ -383,6 +395,11 @@ async def async_step_auth(self, user_input=None):
else:
sound_detection_peak = -50

if CONF_CUSTOM_STREAM in user_input:
custom_stream = user_input[CONF_CUSTOM_STREAM]
else:
custom_stream = ""

if SOUND_DETECTION_DURATION in user_input:
sound_detection_duration = user_input[SOUND_DETECTION_DURATION]
else:
Expand All @@ -404,7 +421,7 @@ async def async_step_auth(self, user_input=None):
raise Exception("Incorrect sound detection peak value.")

rtspStreamWorks = await isRtspStreamWorking(
self.hass, host, username, password
self.hass, host, username, password, custom_stream
)
if not rtspStreamWorks:
raise Exception("Invalid authentication data")
Expand Down Expand Up @@ -434,6 +451,7 @@ async def async_step_auth(self, user_input=None):
SOUND_DETECTION_DURATION: sound_detection_duration,
SOUND_DETECTION_RESET: sound_detection_reset,
CONF_EXTRA_ARGUMENTS: extra_arguments,
CONF_CUSTOM_STREAM: custom_stream,
},
)
return self.async_create_entry(title="", data=None)
Expand Down Expand Up @@ -496,6 +514,10 @@ async def async_step_auth(self, user_input=None):
CONF_EXTRA_ARGUMENTS,
description={"suggested_value": extra_arguments},
): str,
vol.Optional(
CONF_CUSTOM_STREAM,
description={"suggested_value": custom_stream},
): str,
}
),
errors=errors,
Expand Down
1 change: 1 addition & 0 deletions custom_components/tapo_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
CLOUD_PASSWORD = "cloud_password"
DEFAULT_SCAN_INTERVAL = 10
SCAN_INTERVAL = timedelta(seconds=5)
CONF_CUSTOM_STREAM = "custom_stream"

ENABLE_MOTION_SENSOR = "enable_motion_sensor"

Expand Down
6 changes: 4 additions & 2 deletions custom_components/tapo_control/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"sound_detection_peak": "[Sound Detection] Peak in dB. 0 is very loud and -100 is low.",
"sound_detection_duration": "[Sound Detection] How long the noise needs to be over the peak to trigger the state.",
"sound_detection_reset": "[Sound Detection] The time to reset the state after no new noise is over the peak.",
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg"
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg",
"custom_stream": "Custom stream link"
},
"description": "Almost there!\nJust some final options..."
}
Expand Down Expand Up @@ -67,7 +68,8 @@
"sound_detection_duration": "[Sound Detection] How long the noise needs to be over the peak to trigger the state.",
"sound_detection_reset": "[Sound Detection] The time to reset the state after no new noise is over the peak.",
"cloud_password": "Cloud Password (Optional)",
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg"
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg",
"custom_stream": "Custom stream link"
},
"description": "Modify settings of your Tapo Camera.\n\nUse stream from Home Assistant:\nYes - Longer playback delay, lower CPU usage, allows playback control\nNo - Very short playback delay, higher CPU usage, no playback control"
}
Expand Down
6 changes: 4 additions & 2 deletions custom_components/tapo_control/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"sound_detection_peak": "[Sound Detection] Peak in dB. 0 is very loud and -100 is low.",
"sound_detection_duration": "[Sound Detection] How long the noise needs to be over the peak to trigger the state.",
"sound_detection_reset": "[Sound Detection] The time to reset the state after no new noise is over the peak.",
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg"
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg",
"custom_stream": "Custom stream link"
},
"description": "Almost there!\nJust some final options..."
}
Expand Down Expand Up @@ -67,7 +68,8 @@
"sound_detection_peak": "[Sound Detection] Peak in dB. 0 is very loud and -100 is low.",
"sound_detection_duration": "[Sound Detection] How long the noise needs to be over the peak to trigger the state.",
"sound_detection_reset": "[Sound Detection] The time to reset the state after no new noise is over the peak.",
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg"
"extra_arguments": "[Requires restart] Extra arguments for ffmpeg",
"custom_stream": "Custom stream link"
},
"description": "Modify settings of your Tapo Camera.\n\nUse stream from Home Assistant:\nYes - Longer playback delay, lower CPU usage, allows playback control\nNo - Very short playback delay, higher CPU usage, no playback control"
}
Expand Down
10 changes: 8 additions & 2 deletions custom_components/tapo_control/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ def areCameraPortsOpened(host):
return isOpen(host, 443) and isOpen(host, 554) and isOpen(host, 2020)


async def isRtspStreamWorking(hass, host, username, password):
async def isRtspStreamWorking(hass, host, username, password, full_url=""):
_ffmpeg = hass.data[DATA_FFMPEG]
ffmpeg = ImageFrame(_ffmpeg.binary)
username = urllib.parse.quote_plus(username)
password = urllib.parse.quote_plus(password)
streaming_url = f"rtsp://{username}:{password}@{host}:554/stream1"

streaming_url = full_url
if full_url == "":
streaming_url = f"rtsp://{host}:554/stream1"
if username != "" and password != "":
streaming_url = f"rtsp://{username}:{password}@{host}:554/stream1"

image = await asyncio.shield(
ffmpeg.get_image(streaming_url, output_format=IMAGE_JPEG,)
)
Expand Down

0 comments on commit f326870

Please sign in to comment.