Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
JurajNyiri authored and marcosngomezi committed Jul 20, 2024
1 parent 555a6a2 commit 4cb1434
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 24 deletions.
2 changes: 2 additions & 0 deletions custom_components/tapo_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ async def async_update_data():
"downloadProgress": False,
"initialMediaScanDone": False,
"mediaSyncScheduled": False,
"mediaSyncRanOnce": False,
"mediaSyncAvailable": True,
"initialMediaScanRunning": False,
"mediaScanResult": {}, # keeps track of all videos currently on camera
Expand Down Expand Up @@ -688,6 +689,7 @@ async def async_update_data():
# todo move to utils
async def mediaSync(time=None):
LOGGER.debug("mediaSync")
hass.data[DOMAIN][entry.entry_id]["mediaSyncRanOnce"] = True
enableMediaSync = entry.data.get(ENABLE_MEDIA_SYNC)
mediaSyncHours = entry.data.get(MEDIA_SYNC_HOURS)

Expand Down
2 changes: 1 addition & 1 deletion custom_components/tapo_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from homeassistant.helpers import config_validation as cv

PYTAPO_REQUIRED_VERSION = "3.3.21"
PYTAPO_REQUIRED_VERSION = "3.3.22"
DOMAIN = "tapo_control"
BRAND = "TP-Link"
ALARM_MODE = "alarm_mode"
Expand Down
4 changes: 2 additions & 2 deletions custom_components/tapo_control/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"codeowners": [
"@JurajNyiri"
],
"version": "5.4.13",
"version": "5.4.19",
"requirements": [
"pytapo==3.3.21"
"pytapo==3.3.22"
],
"dependencies": [
"ffmpeg",
Expand Down
7 changes: 3 additions & 4 deletions custom_components/tapo_control/media_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
- Handle weird error that sometimes happens causing downloader to get stuck and never recovers until restart
"""


from __future__ import annotations


Expand Down Expand Up @@ -203,9 +202,9 @@ async def async_browse_media(
videoNames = sorted(
videoNames,
key=lambda x: x["startDate"],
reverse=True
if media_view_recordings_order == "Descending"
else False,
reverse=(
True if media_view_recordings_order == "Descending" else False
),
)

dateChildren = []
Expand Down
31 changes: 29 additions & 2 deletions custom_components/tapo_control/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,39 @@ async def async_update(self) -> None:

def updateTapo(self, camData):
enableMediaSync = self._config_entry.data.get(ENABLE_MEDIA_SYNC)
LOGGER.debug(f"Enable Media Sync: {enableMediaSync}")
if enableMediaSync:
LOGGER.debug(
f"Initial Media Scan: {self._hass.data[DOMAIN][self._config_entry.entry_id]['initialMediaScanDone']}"
)
LOGGER.debug(
f"Media Sync Available: {self._hass.data[DOMAIN][self._config_entry.entry_id]['mediaSyncAvailable']}"
)
LOGGER.debug(
f"Download Progress: {self._hass.data[DOMAIN][self._config_entry.entry_id]['downloadProgress']}"
)
LOGGER.debug(
f"Running media sync: {self._hass.data[DOMAIN][self._config_entry.entry_id]['runningMediaSync']}"
)
LOGGER.debug(
f"Media Sync Schedueled: {self._hass.data[DOMAIN][self._config_entry.entry_id]['mediaSyncScheduled']}"
)
LOGGER.debug(
f"Media Sync Ran Once: {self._hass.data[DOMAIN][self._config_entry.entry_id]['mediaSyncRanOnce']}"
)

if not self._hass.data[DOMAIN][self._config_entry.entry_id][
"initialMediaScanDone"
]:
] or (
self._hass.data[DOMAIN][self._config_entry.entry_id][
"initialMediaScanDone"
]
and not self._hass.data[DOMAIN][self._config_entry.entry_id][
"mediaSyncRanOnce"
]
):
self._attr_state = "Starting"
if not self._hass.data[DOMAIN][self._config_entry.entry_id][
elif not self._hass.data[DOMAIN][self._config_entry.entry_id][
"mediaSyncAvailable"
]:
self._attr_state = "No Recordings Found"
Expand Down
42 changes: 27 additions & 15 deletions custom_components/tapo_control/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import time
import urllib.parse
import uuid
import pathlib

from homeassistant.core import HomeAssistant
from homeassistant.config_entries import ConfigEntry
from pytapo.media_stream.downloader import Downloader
Expand Down Expand Up @@ -126,6 +126,7 @@ def getColdDirPathForEntry(hass: HomeAssistant, entry_id: str):
hass.data[DOMAIN][entry_id]["mediaSyncColdDir"] = coldDirPath

coldDirPath = hass.data[DOMAIN][entry_id]["mediaSyncColdDir"]
coldDirPath = coldDirPath.rstrip("/")
return coldDirPath


Expand All @@ -137,6 +138,7 @@ def getHotDirPathForEntry(hass: HomeAssistant, entry_id: str):
hass.data[DOMAIN][entry_id]["mediaSyncHotDir"] = hotDirPath

hotDirPath = hass.data[DOMAIN][entry_id]["mediaSyncHotDir"]
hotDirPath = hotDirPath.rstrip("/")
return hotDirPath


Expand Down Expand Up @@ -262,17 +264,21 @@ async def generateThumb(hass, entry_id, startDate: int, endDate: int):
output_format=IMAGE_JPEG,
)
)
with open(filePathThumb, "wb") as binary_file:
openHandler = await hass.async_add_executor_job(open, filePathThumb, "wb")
with openHandler as binary_file:
binary_file.write(image)
return filePathThumb


# todo: findMedia needs to run periodically because of this function!!!
def deleteFilesNoLongerPresentInCamera(hass, entry_id, extension, folder):
async def deleteFilesNoLongerPresentInCamera(hass, entry_id, extension, folder):
if hass.data[DOMAIN][entry_id]["initialMediaScanDone"] is True:
coldDirPath = getColdDirPathForEntry(hass, entry_id)
if os.path.exists(coldDirPath + "/" + folder + "/"):
for f in os.listdir(coldDirPath + "/" + folder + "/"):
listDirFiles = await hass.async_add_executor_job(
os.listdir, coldDirPath + "/" + folder + "/"
)
for f in listDirFiles:
fileName = f.replace(extension, "")
filePath = os.path.join(coldDirPath + "/" + folder + "/", f)
if fileName not in hass.data[DOMAIN][entry_id]["mediaScanResult"]:
Expand Down Expand Up @@ -304,7 +310,10 @@ async def deleteColdFilesOlderThanMaxSyncTime(hass, entry, extension, folder):
entry_id = entry.entry_id
ts = datetime.datetime.utcnow().timestamp()
if os.path.exists(coldDirPath + "/" + folder + "/"):
for f in os.listdir(coldDirPath + "/" + folder + "/"):
listDirFiles = await hass.async_add_executor_job(
os.listdir, coldDirPath + "/" + folder + "/"
)
for f in listDirFiles:
fileName = f.replace(extension, "")
filePath = os.path.join(coldDirPath + "/" + folder + "/", f)
splitFileName = fileName.split("-")
Expand Down Expand Up @@ -349,11 +358,11 @@ async def mediaCleanup(hass, entry):
LOGGER.debug(
"Removing cache files from old HA instances for entity " + entry_id + "..."
)
deleteFilesNotIncluding(hotDirPath + "/videos/", UUID)
deleteFilesNotIncluding(hotDirPath + "/thumbs/", UUID)
await deleteFilesNotIncluding(hass, hotDirPath + "/videos/", UUID)
await deleteFilesNotIncluding(hass, hotDirPath + "/thumbs/", UUID)

deleteFilesNoLongerPresentInCamera(hass, entry_id, ".mp4", "videos")
deleteFilesNoLongerPresentInCamera(hass, entry_id, ".jpg", "thumbs")
await deleteFilesNoLongerPresentInCamera(hass, entry_id, ".mp4", "videos")
await deleteFilesNoLongerPresentInCamera(hass, entry_id, ".jpg", "thumbs")

await deleteColdFilesOlderThanMaxSyncTime(hass, entry, ".mp4", "videos")
await deleteColdFilesOlderThanMaxSyncTime(hass, entry, ".jpg", "thumbs")
Expand All @@ -366,8 +375,8 @@ async def mediaCleanup(hass, entry):
+ entry_id
+ "..."
)
deleteFilesOlderThan(hotDirPath + "/videos/", HOT_DIR_DELETE_TIME)
deleteFilesOlderThan(hotDirPath + "/thumbs/", HOT_DIR_DELETE_TIME)
await deleteFilesOlderThan(hass, hotDirPath + "/videos/", HOT_DIR_DELETE_TIME)
await deleteFilesOlderThan(hass, hotDirPath + "/thumbs/", HOT_DIR_DELETE_TIME)


def deleteDir(dirPath):
Expand All @@ -381,20 +390,23 @@ def deleteDir(dirPath):
shutil.rmtree(dirPath)


def deleteFilesOlderThan(dirPath, deleteOlderThan):
async def deleteFilesOlderThan(hass: HomeAssistant, dirPath, deleteOlderThan):
now = datetime.datetime.utcnow().timestamp()
if os.path.exists(dirPath):
for f in os.listdir(dirPath):

listDirFiles = await hass.async_add_executor_job(os.listdir, dirPath)
for f in listDirFiles:
filePath = os.path.join(dirPath, f)
last_modified = os.stat(filePath).st_mtime
if now - last_modified > deleteOlderThan:
LOGGER.debug("[deleteFilesOlderThan] Removing " + filePath + "...")
os.remove(filePath)


def deleteFilesNotIncluding(dirPath, includingString):
async def deleteFilesNotIncluding(hass: HomeAssistant, dirPath, includingString):
if os.path.exists(dirPath):
for f in os.listdir(dirPath):
listDirFiles = await hass.async_add_executor_job(os.listdir, dirPath)
for f in listDirFiles:
filePath = os.path.join(dirPath, f)
if includingString not in filePath:
LOGGER.debug("[deleteFilesOlderThan] Removing " + filePath + "...")
Expand Down

0 comments on commit 4cb1434

Please sign in to comment.