Skip to content
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

Add support for notification streams #226

Open
robbinjanssen opened this issue Feb 22, 2024 · 3 comments
Open

Add support for notification streams #226

robbinjanssen opened this issue Feb 22, 2024 · 3 comments
Labels
new-feature New features or options. no-stale This issue or PR is exempted from the stable bot.

Comments

@robbinjanssen
Copy link
Owner

robbinjanssen commented Feb 22, 2024

Both WD5 and WD4 have support for notification streams. Basically this is a HTTP GET call that is kept-alive and keeps receiving JSON updates about thermostats.

  1. Where do we put this code, ojmicroline.py is currently responsible for data-fetching, however since both WD4 and WD5 are pretty different (1 call vs 3 calls), im not sure where to put it. @adamjernst any suggestions?
  2. Then we need to figure out what HA requires for these push updates. I think we need to implement something like registration for listeners and callbacks to those listeners?

For WD5 this is a POC:

async def get_stream_connection(
    self, 
    session_id: str,
    session: ClientSession
) -> Any:
    async with async_timeout.timeout(30):
        # Negotiate
        url = URL.build(
            scheme="https", 
            host=self.host, 
            path="/ocd5notification/negotiate",
            query={"clientProtocol": "1.3"}
        )
        
        response = await session.request(method="GET", url=url, ssl=True)
        response.raise_for_status()

        data = json.loads(await response.text());
        connectionId = data['ConnectionId']
        connectionToken = data['ConnectionToken']
    
        # Start
        url = URL.build(
            scheme="https", 
            host=self.host, 
            path="/ocd5notification/send",
            query={
                "transport": "serverSentEvents",
                "connectionToken": connectionToken,
                "connectionId": connectionId,
            },
        )

        response = await session.request(
            method="POST",
            url=url, 
            headers={"Content-Type": "application/x-www-form-urlencoded"}, 
            data=f"data={session_id}",
            ssl=True
        )
        response.raise_for_status()

        # Connect to stream
        url = URL.build(
            scheme="https", 
            host=self.host, 
            path="/ocd5notification/connect",
            query={
                "transport": "serverSentEvents",
                "connectionToken": connectionToken,
                "connectionId": connectionId,
            },
        )

        response = await session.request(method="GET", url=url, headers={"Accept":"text/event-stream"}, ssl=True)
        response.raise_for_status()

        async for line in response.content:
            data = line.decode('ascii').strip()
            if (data == ""):
                continue

            data = data[6:]
            if data != 'initialized':
                data = json.loads(data)
            
            if "M" not in data:
                continue
            
            for event in data["M"]:
                print(json.dumps(event, indent=2))
@adamjernst
Copy link
Contributor

Where do we put this code

I'm not sure but my first impulse is to add a method to the OJMicrolineAPI protocol, but keep most of the actual code in the respective WD5 and WG4 classes (which live in separate files). Use shared helper methods for any similar functionality.

i.e. keep ojmicroline.py pretty dumb and simple, and all the loop/keepalive management/etc in the wd5/wg4 classes, especially since the two models are so different

@adamjernst
Copy link
Contributor

I think we need to implement something like registration for listeners and callbacks to those listeners?

Good question. I am not sure what the most Pythonic way to represent this is with asyncio. I guess check out some HA integrations that do similar push stuff and copy their approach?

Copy link

There hasn't been any activity on this issue recently, so we clean up some of the older and inactive issues.
Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by leaving a comment 👍
This issue has now been marked as stale and will be closed if no further activity occurs. Thanks!

@github-actions github-actions bot added the stale There has not been activity on this issue or PR for quite some time. label Mar 26, 2024
@robbinjanssen robbinjanssen added no-stale This issue or PR is exempted from the stable bot. and removed stale There has not been activity on this issue or PR for quite some time. labels Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new-feature New features or options. no-stale This issue or PR is exempted from the stable bot.
Projects
None yet
Development

No branches or pull requests

2 participants