Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions aiocomfoconnect/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" aiocomfoconnect CLI application """
"""aiocomfoconnect CLI application"""

from __future__ import annotations

Expand Down Expand Up @@ -84,26 +84,18 @@ async def run_register(host: str, uuid: str, name: str, pin: int):
raise BridgeNotFoundException("No bridge found")

# Connect to the bridge
comfoconnect = ComfoConnect(bridges[0].host, bridges[0].uuid)
comfoconnect = ComfoConnect(bridges[0].host, bridges[0].uuid, bridge_type=bridges[0].bridge_type)

try:
# Login with the bridge
await comfoconnect.connect(uuid)
print(f"UUID {uuid} is already registered.")

registered = await comfoconnect.register(uuid, name, pin)
except ComfoConnectNotAllowed:
# We probably are not registered yet...
try:
await comfoconnect.cmd_register_app(uuid, name, pin)
except ComfoConnectNotAllowed:
await comfoconnect.disconnect()
print("Registration failed. Please check the PIN.")
sys.exit(1)
print("Registration failed. Please check the PIN.")
sys.exit(1)

if registered:
print(f"UUID {uuid} is now registered.")

# Connect to the bridge
await comfoconnect.cmd_start_session(True)
else:
print(f"UUID {uuid} is already registered.")

# ListRegisteredApps
print()
Expand Down Expand Up @@ -296,7 +288,7 @@ def sensor_callback(sensor_, value):
print("Could not connect to bridge. Please register first.")
sys.exit(1)

if not sensor in SENSORS:
if sensor not in SENSORS:
print(f"Unknown sensor with ID {sensor}")
sys.exit(1)

Expand Down
38 changes: 36 additions & 2 deletions aiocomfoconnect/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
_LOGGER = logging.getLogger(__name__)

TIMEOUT = 5
GATEWAY_TYPE_PRO = 2

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to get this from the protobuf file.



class SelfDeregistrationError(Exception):
Expand Down Expand Up @@ -76,13 +77,20 @@ def fail_all(self, exc: Exception):


class Bridge:
"""ComfoConnect LAN C API."""
"""ComfoConnect LAN C / PRO API."""

PORT = 56747

def __init__(self, host: str, uuid: str, loop: Optional[asyncio.AbstractEventLoop] = None):
def __init__(
self,
host: str,
uuid: str,
loop: Optional[asyncio.AbstractEventLoop] = None,
bridge_type: int = 0,
):
self.host: str = host
self.uuid: str = uuid
self.bridge_type: int = bridge_type
self._local_uuid: Optional[str] = None

self._reader: Optional[StreamReader] = None
Expand Down Expand Up @@ -110,6 +118,32 @@ def set_alarm_callback(self, callback: Optional[Callable[[int, ProtobufMessage],

async def connect(self, uuid: str):
"""Connect to the bridge and start reading messages."""
await self._open_connection(uuid)

async def register(self, uuid: str, name: str, pin: int) -> bool:
"""Register this app on the bridge and start a session.

For LAN C bridges, attempts to start a session first; if the session
succeeds the app is already registered and no re-registration occurs.
For Pro bridges, registers directly to avoid a connection timeout that
the Pro issues when the app is not yet registered.

Returns True if the app was newly registered, False if it was already registered.
"""
await self._open_connection(uuid)
if self.bridge_type != GATEWAY_TYPE_PRO:
# LAN C: check whether we are already registered by starting a session.
try:
await self.cmd_start_session(True)
return False # Already registered; session is now active.
except ComfoConnectNotAllowed:
pass # Not registered yet; fall through to register below.
Comment on lines +134 to +140

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are ok with changing the actual behaviour, we could get rid of this part. I'm not really sure how that would work on the LAN C tho.

await self.cmd_register_app(uuid, name, pin)
await self.cmd_start_session(True)
return True

async def _open_connection(self, uuid: str):
"""Open TCP connection to the bridge and start reading messages."""
if self.is_connected():
_LOGGER.warning("Already connected to bridge %s", self.host)
return
Expand Down
4 changes: 2 additions & 2 deletions aiocomfoconnect/comfoconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
class ComfoConnect(Bridge):
"""Abstraction layer over the ComfoConnect LAN C API."""

def __init__(self, host: str, uuid: str, loop=None, sensor_callback=None, alarm_callback=None, sensor_delay=2, connect_timeout=30):
def __init__(self, host: str, uuid: str, loop=None, sensor_callback=None, alarm_callback=None, sensor_delay=2, connect_timeout=30, bridge_type: int = 0):
"""Initialize the ComfoConnect class."""
super().__init__(host, uuid, loop)
super().__init__(host, uuid, loop, bridge_type)

self.set_sensor_callback(self._sensor_callback) # Set the callback to our _sensor_callback method, so we can proces the callbacks.
self.set_alarm_callback(self._alarm_callback) # Set the callback to our _alarm_callback method, so we can proces the callbacks.
Expand Down
10 changes: 8 additions & 2 deletions aiocomfoconnect/discovery.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Bridge discovery """
"""Bridge discovery"""

from __future__ import annotations

Expand Down Expand Up @@ -48,7 +48,13 @@ def datagram_received(self, data: Union[bytes, str], addr: tuple[str | Any, int]
parser = zehnder_pb2.DiscoveryOperation() # pylint: disable=no-member
parser.ParseFromString(data)

self._bridges.append(Bridge(host=parser.searchGatewayResponse.ipaddress, uuid=parser.searchGatewayResponse.uuid.hex()))
self._bridges.append(
Bridge(
host=parser.searchGatewayResponse.ipaddress,
uuid=parser.searchGatewayResponse.uuid.hex(),
bridge_type=parser.searchGatewayResponse.type,
)
)

# When we have passed a target, we only want to listen for that one
if self._target:
Expand Down
338 changes: 169 additions & 169 deletions aiocomfoconnect/protobuf/zehnder_pb2.py

Large diffs are not rendered by default.

49 changes: 25 additions & 24 deletions protobuf/zehnder.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ message SearchGatewayResponse {
enum GatewayType {
lanc = 0;
season = 1;
pro = 2;
}
required string ipaddress = 1 [(nanopb).max_size = 16];
required bytes uuid = 2 [(nanopb).max_size = 16];
Expand All @@ -32,7 +33,7 @@ message SearchGatewayResponse {
///////////////////////////////////////////////////////////////////////////////////////////////////
message GatewayOperation {
enum OperationType {
NoOperation = 0;
NoOperation = 0;

SetAddressRequestType = 1;
RegisterAppRequestType = 2;
Expand Down Expand Up @@ -138,11 +139,11 @@ message GatewayOperation {
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// This is the base-message for all notifications.
// This is the base-message for all notifications.
// The Gateway sends this message to the Backend and the connected App (if any).
// The Gateway specifies the list of currently registered PushUUIDs in this message.
// The Gateway specifies the list of currently registered PushUUIDs in this message.
// The Backend uses this list to send out the push-notifications if needed (depending on the contents of the push-message).
// TODO: Tell Gateway which notifications to forward to the Backend and which to forward to the App only
// TODO: Tell Gateway which notifications to forward to the Backend and which to forward to the App only
///////////////////////////////////////////////////////////////////////////////////////////////////
message GatewayNotification {
repeated bytes pushUUIDs = 1;
Expand Down Expand Up @@ -177,7 +178,7 @@ message SetDeviceSettingsConfirm {
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Associates a GatewayUUID or AppUUID with a Backend-connection.
// Associates a GatewayUUID or AppUUID with a Backend-connection.
// This way the Backend knows on which TCP-connection the specified UUID can be reached.
//
// Authentication:
Expand Down Expand Up @@ -231,7 +232,7 @@ message StartSessionConfirm {

///////////////////////////////////////////////////////////////////////////////////////////////////
// Inform other side that the session is closed. CloseSessionConfirm is only sent back when
// an error occurred.
// an error occurred.
//
// Authentication:
// None
Expand Down Expand Up @@ -262,13 +263,13 @@ message ListRegisteredAppsConfirm {
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Used to deregister a mobile app from the Gateway.
// The Gateway removes the specified uuid from the list of registered AppUUIDs.
// Used to deregister a mobile app from the Gateway.
// The Gateway removes the specified uuid from the list of registered AppUUIDs.
// The devicename for this uuid is also removed.
//
// Authentication:
// This message is authenticated by srcuuid (must be a registered AppUUID or WebUUID).
// SupportUUID is not allowed.
// SupportUUID is not allowed.
///////////////////////////////////////////////////////////////////////////////////////////////////
message DeregisterAppRequest {
required bytes uuid = 1 [(nanopb).max_size = 16];
Expand All @@ -295,7 +296,7 @@ message ChangePinConfirm {

///////////////////////////////////////////////////////////////////////////////////////////////////
// This returns the currently set RemoteUUID at the Gateway or nothing if not set.
//
//
// Authentication:
// This message is authenticated by srcuuid (must be a registered AppUUID).
// SupportUUID/WebUUID are not allowed.
Expand All @@ -309,14 +310,14 @@ message GetRemoteAccessIdConfirm {

///////////////////////////////////////////////////////////////////////////////////////////////////
// The RemoteUUID is set at the Gateway when the user enables remote access from the App.
// The Gateway stores the RemoteUUID in eeprom/flash and uses it to set its address at the Backend.
// When the Gateway has not received a RemoteUUID yet, it cannot set the address at the Backend and
// The Gateway stores the RemoteUUID in eeprom/flash and uses it to set its address at the Backend.
// When the Gateway has not received a RemoteUUID yet, it cannot set the address at the Backend and
// therefore there is no need to setup the connection to the Backend.
// The App uses this RemoteUUID to gain access to the Gateway via the Backend.
// The App uses this RemoteUUID to gain access to the Gateway via the Backend.
// The Backend routes messages from the App to the Gateway that registered this id with SetAddress.
// Setting the RemoteUUID to a new value requires other Apps that still use the old value (or no value)
// Setting the RemoteUUID to a new value requires other Apps that still use the old value (or no value)
// to get an updated RemoteAccessId.
// Remote access can be disabled by keeping the uuid in the request empty. In this case the Gateway
// Remote access can be disabled by keeping the uuid in the request empty. In this case the Gateway
// will remove the current RemoteUUID (if any) and close the connection to the Backend.
//
// Authentication:
Expand Down Expand Up @@ -346,9 +347,9 @@ message GetSupportIdConfirm {

///////////////////////////////////////////////////////////////////////////////////////////////////
// The SupportUUID is set at the Gateway when the user enables remote support from the App.
// The Gateway stores the SupportUUID in eeprom/flash and uses it to authenticate incoming
// The Gateway stores the SupportUUID in eeprom/flash and uses it to authenticate incoming
// requests (same way as AppUUID, WebUUID).
// The SupportUUID is only valid for a limited time (to be determined).
// The SupportUUID is only valid for a limited time (to be determined).
// The Gateway is responsible from removing the SupportUUID when the time is expired.
// The SupportUUID can be removed from the Gateway by keeping the uuid in the request empty.
//
Expand All @@ -365,7 +366,7 @@ message SetSupportIdConfirm {

///////////////////////////////////////////////////////////////////////////////////////////////////
// This returns the currently set WebUUID at the Gateway or nothing if not set.
//
//
// Authentication:
// This message is authenticated by srcuuid (must be a registered AppUUID).
///////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -392,12 +393,12 @@ message SetWebIdConfirm {
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// The PushUUID is set at the Gateway when the user enables push-support in the App.
// The PushUUID is set at the Gateway when the user enables push-support in the App.
// Multiple PushUUIDs can be set at the Gateway (one per AppUUID).
// The Gateway stores the PushUUIDs in eeprom/flash and uses them when a notification is received
// from the ComfoNet-side. The notification is forwarded to the Backend and the connected App (if any)
// The Gateway stores the PushUUIDs in eeprom/flash and uses them when a notification is received
// from the ComfoNet-side. The notification is forwarded to the Backend and the connected App (if any)
// using the GatewayNotification (see TODO) messages.
// The PushUUID can be removed from the Gateway by keeping the uuid in the request empty
// The PushUUID can be removed from the Gateway by keeping the uuid in the request empty
// (for the AppUUID indicated by the srcuuid).
//
// Authentication:
Expand Down Expand Up @@ -700,12 +701,12 @@ message WiFiNetworksConfirm {

message WiFiJoinNetworkRequest {
required WiFiMode mode = 1;
optional string ssid = 2 [(nanopb).max_size = 32];
optional string ssid = 2 [(nanopb).max_size = 32];
optional string password = 3 [(nanopb).max_size = 64];
optional WiFiSecurity security = 4 [default = WPA_WPA2];
}

message WiFiJoinNetworkConfirm {
message WiFiJoinNetworkConfirm {
}


Expand Down
Loading