fronzbot / blinkpy

A Python library for the Blink Camera system
MIT License
558 stars 117 forks source link

Cannot retrieve sync modules #957

Closed apach3guy closed 3 months ago

apach3guy commented 3 months ago

A previously working script stopped working. Now I can't even get blinkpy to load any sync modules (I have 2 under my account). Did blink deprecate the sync module API used by blinkpy? I attached my code and the output is below.

Authentication successful.
Available sync modules after blink.start():
No sync modules available. Check your Blink setup.
#!/usr/bin/env python3

import asyncio
from datetime import datetime, timedelta
from sortedcontainers import SortedSet
from blinkpy.helpers.util import json_load
from blinkpy.blinkpy import Blink, BlinkSyncModule
from blinkpy.auth import Auth
import aiohttp
import blinkpy.api as api

async def custom_http_get(blink, url, is_retry=False):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            if response.headers['Content-Type'] == 'application/json':
                return await response.json()
            else:
                text = await response.text()
                raise aiohttp.client_exceptions.ContentTypeError(
                    response.request_info, response.history,
                    message=f"Unexpected content type: {response.headers['Content-Type']}",
                    text=text
                )

# Override the default http_get function in the blinkpy.api module
api.http_get = custom_http_get

async def start():
    async with aiohttp.ClientSession() as session:
        blink = Blink()
        try:
            auth_data = await json_load("/home/pi/utils/blink.auth")
            blink.auth = Auth(auth_data, session=session)
            await blink.start()
            print("Authentication successful.")
        except Exception as e:
            print(f"Authentication failed: {e}")
            return

        await blink.refresh()

        # Print out available sync module names for debugging
        print("Available sync modules after blink.start():")
        for sync_module_name in blink.sync:
            print(sync_module_name)

        # Check if any sync modules are available
        if not blink.sync:
            print("No sync modules available. Check your Blink setup.")
            return

        # Use the actual sync module name instead of 'Laguna'
        sync_module_name = "Laguna"  # Replace with the correct name after debugging
        if sync_module_name in blink.sync:
            my_sync: BlinkSyncModule = blink.sync[sync_module_name]
        else:
            raise KeyError(f"Sync module '{sync_module_name}' not found. Available modules: {list(blink.sync.keys())}")

        my_sync._local_storage["manifest"] = SortedSet()
        await my_sync.refresh()
        print(f"Manifest {my_sync._local_storage['manifest']}")
        manifest = my_sync._local_storage["manifest"]
        for item in reversed(manifest):
            current_date = datetime.now(item.created_at.tzinfo)
            time_difference = current_date - item.created_at
            if time_difference > timedelta(days=14):
                await item.delete_video(blink)
                await asyncio.sleep(2)

asyncio.run(start())
fronzbot commented 3 months ago

What version was it previously working with and what version broke? To my knowledge nothing has changed with the API. At first glance this looks like it could be an async issue where you're waiting for the refresh/start to complete but are checking the blink.sync property too soon. For debug, try adding a time.sleep(10) before checking if sync modules exist.

apach3guy commented 3 months ago

I'm using blinkpy 0.22.0. I did not upgrade the package or python. It just stopped working.

I added the 10 second sleep, but still no sync modules are found.

#!/usr/bin/env python3

import asyncio
from datetime import datetime, timedelta
from sortedcontainers import SortedSet
from blinkpy.helpers.util import json_load
from blinkpy.blinkpy import Blink, BlinkSyncModule
from blinkpy.auth import Auth
import aiohttp
import blinkpy.api as api
import time

async def custom_http_get(blink, url, is_retry=False):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            if response.headers['Content-Type'] == 'application/json':
                return await response.json()
            else:
                text = await response.text()
                raise aiohttp.client_exceptions.ContentTypeError(
                    response.request_info, response.history,
                    message=f"Unexpected content type: {response.headers['Content-Type']}",
                    text=text
                )

# Override the default http_get function in the blinkpy.api module
api.http_get = custom_http_get

async def start():
    async with aiohttp.ClientSession() as session:
        blink = Blink()
        try:
            auth_data = await json_load("/home/pi/utils/blink.auth")
            blink.auth = Auth(auth_data, session=session)
            await blink.start()
            print("Authentication successful.")
        except Exception as e:
            print(f"Authentication failed: {e}")
            return

        await blink.refresh()

        time.sleep(10)

        # Print out available sync module names for debugging
        print("Available sync modules after blink.start():")
        for sync_module_name in blink.sync:
            print(sync_module_name)

        # Check if any sync modules are available
        if not blink.sync:
            print("No sync modules available. Check your Blink setup.")
            return

        # Use the actual sync module name instead of 'Laguna'
        sync_module_name = "Laguna"  # Replace with the correct name after debugging
        if sync_module_name in blink.sync:
            my_sync: BlinkSyncModule = blink.sync[sync_module_name]
        else:
            raise KeyError(f"Sync module '{sync_module_name}' not found. Available modules: {list(blink.sync.keys())}")

        my_sync._local_storage["manifest"] = SortedSet()
        await my_sync.refresh()
        print(f"Manifest {my_sync._local_storage['manifest']}")
        manifest = my_sync._local_storage["manifest"]
        for item in reversed(manifest):
            current_date = datetime.now(item.created_at.tzinfo)
            time_difference = current_date - item.created_at
            if time_difference > timedelta(days=14):
                await item.delete_video(blink)
                await asyncio.sleep(2)

asyncio.run(start())
fronzbot commented 3 months ago

Oh, since 0.22.0 there definitely have been API changes (that version is almost a year old). Not sure if they're the root cause here, but please update to the latest version 0.23.0 and see if you still have the problem.

Also, why are you overriding the default http_get method? For debug it would be a good idea to use the library as barebones as possible to eliminate any external factors from being a source of error

apach3guy commented 3 months ago

Thanks. Upgraded to python 3.9 and installed the latest dev version of blinkpy. Working code below.

#!/usr/bin/env python3.9

import asyncio
from datetime import datetime, timedelta
from sortedcontainers import SortedSet
from blinkpy.helpers.util import json_load
from blinkpy.blinkpy import Blink, BlinkSyncModule
from blinkpy.auth import Auth
from aiohttp import ClientSession

async def start(session: ClientSession):
    """Startup blink app."""
    blink = Blink(session=session)
    blink.auth = Auth(await json_load("/home/pi/utils/blink.auth"), session=session)
    await blink.start()
    return blink

async def main():
    session = ClientSession()
    try:
        blink = await start(session)
        await blink.refresh()
        my_sync: BlinkSyncModule = blink.sync["Laguna"]
        await my_sync.refresh()
        if my_sync.local_storage and my_sync.local_storage_manifest_ready:
            manifest = my_sync._local_storage["manifest"]
            # print(f"Manifest {manifest}")
            for item in reversed(manifest):
                current_date = datetime.now(item.created_at.tzinfo)
                time_difference = current_date - item.created_at

                if time_difference > timedelta(days=14):
                    try:
                        await item.delete_video(blink)
                        await asyncio.sleep(2)
                    except Exception as e:
                        print(f"Error deleting video {item.id}: {e}")
        else:
            print("Manifest not ready")
    finally:
        await session.close()

asyncio.run(main())