Skip to content

Commit

Permalink
Refactor async initialization methods and update README examples
Browse files Browse the repository at this point in the history
  • Loading branch information
hahn-th committed Feb 22, 2025
1 parent c8d9e08 commit d3cb1ee
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 57 deletions.
40 changes: 20 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,26 +260,26 @@ It’s also possible to use push notifications based on a websocket connection:

```python
# Example function to display incoming events.
def print_events(event_list):
for event in event_list:
print("EventType: {} Data: {}".format(event["eventType"], event["data"]))


# Initialise the API.
config = homematicip.find_and_load_config_file()
home = Home()
home.set_auth_token(config.auth_token)
home.init(config.access_point)

# Add function to handle events and start the connection.
home.onEvent += print_events
home.enable_events()

try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Interrupt.")
def print_events(event_list):
for event in event_list:
print("EventType: {} Data: {}".format(event["eventType"], event["data"]))


# Initialise the API.
config = homematicip.find_and_load_config_file()
home = Home()
home.set_auth_token(config.auth_token)
home.init(config.access_point)

# Add function to handle events and start the connection.
home.onEvent += print_events
home.enable_events()

try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Interrupt.")
```

## Pathes for config.ini
Expand Down
2 changes: 1 addition & 1 deletion bin/homematicip_cli_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async def get_home(loop):

home = AsyncHome(loop)
home.set_auth_token(_config.auth_token)
await home.init(_config.access_point)
await home.init_async(_config.access_point)
return home


Expand Down
6 changes: 3 additions & 3 deletions src/homematicip/async_home.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from typing import List, Callable

from homematicip.EventHook import *
Expand Down Expand Up @@ -74,14 +73,15 @@ def __init__(self, connection=None):
self.rules = []
self.functionalHomes = []

def init(self, access_point_id, auth_token: str | None = None, lookup=True, use_rate_limiting=True):
async def init_async(self, access_point_id, auth_token: str | None = None, lookup=True, use_rate_limiting=True):
"""Initializes the home with the given access point id and auth token
:param access_point_id: the access point id
:param auth_token: the auth token
:param lookup: if set to true, the urls will be looked up
:param use_rate_limiting: if set to true, the connection will be rate limited
"""
self._connection_context = ConnectionContextBuilder.build_context(accesspoint_id=access_point_id, auth_token=auth_token)
self._connection_context = await ConnectionContextBuilder.build_context_async(accesspoint_id=access_point_id,
auth_token=auth_token)
self._connection = ConnectionFactory.create_connection(self._connection_context, use_rate_limiting)

def init_with_context(self, context: ConnectionContext, use_rate_limiting=True):
Expand Down
2 changes: 1 addition & 1 deletion src/homematicip/cli/hmip_generate_auth_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async def run_auth(access_point: str = None, devicename: str = None, pin: str =
continue
break

context = ConnectionContextBuilder.build_context(access_point)
context = await ConnectionContextBuilder.build_context_async(access_point)
connection = RestConnection(context, log_status_exceptions=False)

auth = homematicip.auth.Auth(connection, context.client_auth_token, access_point)
Expand Down
59 changes: 30 additions & 29 deletions src/homematicip/connection/connection_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
class ConnectionContextBuilder:

@classmethod
def build_context(cls, accesspoint_id: str,
lookup_url: str = "https://lookup.homematic.com:48335/getHost",
auth_token: str = None,
enforce_ssl: bool = True,
ssl_ctx=None):
async def build_context_async(cls, accesspoint_id: str,
lookup_url: str = "https://lookup.homematic.com:48335/getHost",
auth_token: str = None,
enforce_ssl: bool = True,
ssl_ctx=None):
"""
Create a new connection context and lookup urls
Expand All @@ -30,52 +30,53 @@ def build_context(cls, accesspoint_id: str,
ctx.enforce_ssl = enforce_ssl

cc = ClientCharacteristicsBuilder.get(accesspoint_id)
ctx.rest_url, ctx.websocket_url = ConnectionUrlResolver().lookup_urls(cc, lookup_url, enforce_ssl, ssl_ctx)
ctx.rest_url, ctx.websocket_url = await ConnectionUrlResolver().lookup_urls_async(cc, lookup_url, enforce_ssl,
ssl_ctx)

if auth_token is not None:
ctx.auth_token = auth_token

return ctx


@dataclass
class ConnectionContext:
auth_token: str = None
client_auth_token: str = None

websocket_url: str = "ws://localhost:8765"
rest_url: str = None
accesspoint_id: str = None

enforce_ssl: bool = True
ssl_ctx = None

@classmethod
def create(cls, access_point_id: str,
lookup_url: str = "https://lookup.homematic.com:48335/getHost",
auth_token: str = None,
enforce_ssl: bool = True,
ssl_ctx=None):
def build_context(cls, accesspoint_id: str,
lookup_url: str = "https://lookup.homematic.com:48335/getHost",
auth_token: str = None,
enforce_ssl: bool = True,
ssl_ctx=None):
"""
Create a new connection context.
Create a new connection context and lookup urls
:param access_point_id: Access point id
:param accesspoint_id: Access point id
:param lookup_url: Url to lookup the connection urls
:param auth_token: The Auth Token if exists. If no one is provided None will be used
:param enforce_ssl: Disable ssl verification by setting enforce_ssl to False
:param ssl_ctx: ssl context to use
:return: a new ConnectionContext
"""
ctx = ConnectionContext()
ctx.accesspoint_id = access_point_id
ctx.client_auth_token = ClientTokenBuilder.build_client_token(access_point_id)
ctx.accesspoint_id = accesspoint_id
ctx.client_auth_token = ClientTokenBuilder.build_client_token(accesspoint_id)
ctx.ssl_ctx = ssl_ctx
ctx.enforce_ssl = enforce_ssl

cc = ClientCharacteristicsBuilder.get(access_point_id)
cc = ClientCharacteristicsBuilder.get(accesspoint_id)
ctx.rest_url, ctx.websocket_url = ConnectionUrlResolver().lookup_urls(cc, lookup_url, enforce_ssl, ssl_ctx)

if auth_token is not None:
ctx.auth_token = auth_token

return ctx


@dataclass
class ConnectionContext:
auth_token: str = None
client_auth_token: str = None

websocket_url: str = "ws://localhost:8765"
rest_url: str = None
accesspoint_id: str = None

enforce_ssl: bool = True
ssl_ctx = None
33 changes: 31 additions & 2 deletions src/homematicip/connection/connection_url_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,41 @@
class ConnectionUrlResolver:
"""Lookup rest and websocket urls."""

@staticmethod
async def lookup_urls_async(
client_characteristics: dict,
lookup_url: str,
enforce_ssl: bool = True,
ssl_context: SSLContext = None,
) -> tuple[str, str]:
"""Lookup urls async.
:param client_characteristics: The client characteristics
:param lookup_url: The lookup url
:param enforce_ssl: Disable ssl verification by setting enforce_ssl to False
:param ssl_context: The ssl context
:return: The rest and websocket url as tuple
"""
verify = ConnectionUrlResolver._get_verify(enforce_ssl, ssl_context)

async with httpx.AsyncClient(verify=verify) as client:
result = await client.post(lookup_url, json=client_characteristics)
result.raise_for_status()

js = result.json()

rest_url = js["urlREST"]
websocket_url = js["urlWebSocket"]

return rest_url, websocket_url

@staticmethod
def lookup_urls(
client_characteristics: dict,
lookup_url: str,
enforce_ssl: bool = True,
ssl_context = None,
ssl_context=None,
) -> tuple[str, str]:
"""Lookup urls.
Expand Down Expand Up @@ -40,4 +69,4 @@ def _get_verify(enforce_ssl: bool, ssl_context):
if enforce_ssl:
return enforce_ssl

return True
return True
3 changes: 3 additions & 0 deletions src/homematicip/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
class Home(AsyncHome):
"""this class represents the 'Home' of the homematic ip"""

def init(self, access_point_id, auth_token: str | None = None, lookup=True, use_rate_limiting=True):
return self._run_non_async(self.init_async, access_point_id, auth_token, lookup, use_rate_limiting)

def activate_absence_permanent(self):
return self._run_non_async(self.activate_absence_permanent_async)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

def test_init():
context = ConnectionContext(auth_token="auth_token", accesspoint_id="access_point_id")
with patch('homematicip.connection.connection_context.ConnectionContextBuilder.build_context',
with patch('homematicip.connection.connection_context.ConnectionContextBuilder.build_context_async',
return_value=context) as mock_create:
home = Home()
home.init('access_point_id', 'auth_token')
Expand Down

0 comments on commit d3cb1ee

Please sign in to comment.