eero-api 1.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
eero/__init__.py ADDED
@@ -0,0 +1,25 @@
1
+ """Eero API - Async Python client for Eero mesh WiFi networks."""
2
+
3
+ from .api import EeroAPI
4
+ from .client import EeroClient
5
+ from .exceptions import (
6
+ EeroAPIException,
7
+ EeroAuthenticationException,
8
+ EeroException,
9
+ EeroNetworkException,
10
+ EeroRateLimitException,
11
+ EeroTimeoutException,
12
+ )
13
+
14
+ __all__ = [
15
+ "EeroAPI",
16
+ "EeroClient",
17
+ "EeroException",
18
+ "EeroAPIException",
19
+ "EeroAuthenticationException",
20
+ "EeroNetworkException",
21
+ "EeroRateLimitException",
22
+ "EeroTimeoutException",
23
+ ]
24
+
25
+ __version__ = "1.2.4"
eero/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Command-line entry point for the Eero API package."""
2
+
3
+ from .cli.main import cli
4
+
5
+ if __name__ == "__main__":
6
+ cli()
eero/api/__init__.py ADDED
@@ -0,0 +1,137 @@
1
+ """API module for Eero."""
2
+
3
+ from typing import Optional
4
+
5
+ from aiohttp import ClientSession
6
+
7
+ from .ac_compat import ACCompatAPI
8
+ from .activity import ActivityAPI
9
+ from .auth import AuthAPI
10
+ from .backup import BackupAPI
11
+ from .blacklist import BlacklistAPI
12
+ from .burst_reporters import BurstReportersAPI
13
+ from .devices import DevicesAPI
14
+ from .diagnostics import DiagnosticsAPI
15
+ from .dns import DnsAPI
16
+ from .eeros import EerosAPI
17
+ from .forwards import ForwardsAPI
18
+ from .insights import InsightsAPI
19
+ from .networks import NetworksAPI
20
+ from .ouicheck import OUICheckAPI
21
+ from .password import PasswordAPI
22
+ from .profiles import ProfilesAPI
23
+ from .reservations import ReservationsAPI
24
+ from .routing import RoutingAPI
25
+ from .schedule import ScheduleAPI
26
+ from .security import SecurityAPI
27
+ from .settings import SettingsAPI
28
+ from .sqm import SqmAPI
29
+ from .support import SupportAPI
30
+ from .thread import ThreadAPI
31
+ from .transfer import TransferAPI
32
+ from .updates import UpdatesAPI
33
+
34
+
35
+ class EeroAPI:
36
+ """API client for interacting with the Eero API."""
37
+
38
+ def __init__(
39
+ self,
40
+ session: Optional[ClientSession] = None,
41
+ cookie_file: Optional[str] = None,
42
+ use_keyring: bool = True,
43
+ ) -> None:
44
+ """Initialize the EeroAPI.
45
+
46
+ Args:
47
+ session: Optional aiohttp ClientSession to use for requests
48
+ cookie_file: Optional path to a file for storing authentication cookies
49
+ use_keyring: Whether to use keyring for secure token storage
50
+ """
51
+ self.auth = AuthAPI(session, cookie_file, use_keyring)
52
+ self.activity = ActivityAPI(self.auth)
53
+ self.backup = BackupAPI(self.auth)
54
+ self.dns = DnsAPI(self.auth)
55
+ self.networks = NetworksAPI(self.auth)
56
+ self.devices = DevicesAPI(self.auth)
57
+ self.eeros = EerosAPI(self.auth)
58
+ self.profiles = ProfilesAPI(self.auth)
59
+ self.schedule = ScheduleAPI(self.auth)
60
+ self.security = SecurityAPI(self.auth)
61
+ self.sqm = SqmAPI(self.auth)
62
+ self.diagnostics = DiagnosticsAPI(self.auth)
63
+ self.settings = SettingsAPI(self.auth)
64
+ self.updates = UpdatesAPI(self.auth)
65
+ self.insights = InsightsAPI(self.auth)
66
+ self.routing = RoutingAPI(self.auth)
67
+ self.thread = ThreadAPI(self.auth)
68
+ self.support = SupportAPI(self.auth)
69
+ self.blacklist = BlacklistAPI(self.auth)
70
+ self.reservations = ReservationsAPI(self.auth)
71
+ self.forwards = ForwardsAPI(self.auth)
72
+ self.transfer = TransferAPI(self.auth)
73
+ self.burst_reporters = BurstReportersAPI(self.auth)
74
+ self.ac_compat = ACCompatAPI(self.auth)
75
+ self.ouicheck = OUICheckAPI(self.auth)
76
+ self.password = PasswordAPI(self.auth)
77
+
78
+ async def __aenter__(self) -> "EeroAPI":
79
+ """Enter async context manager."""
80
+ await self.auth.__aenter__()
81
+ return self
82
+
83
+ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
84
+ """Exit async context manager."""
85
+ await self.auth.__aexit__(exc_type, exc_val, exc_tb)
86
+
87
+ @property
88
+ def is_authenticated(self) -> bool:
89
+ """Check if the client is authenticated."""
90
+ return self.auth.is_authenticated
91
+
92
+ async def login(self, user_identifier: str) -> bool:
93
+ """Start the login process by requesting a verification code.
94
+
95
+ Args:
96
+ user_identifier: Email address or phone number for the Eero account
97
+
98
+ Returns:
99
+ True if login request was successful
100
+ """
101
+ return await self.auth.login(user_identifier)
102
+
103
+ async def verify(self, verification_code: str) -> bool:
104
+ """Verify login with the code sent to the user.
105
+
106
+ Args:
107
+ verification_code: The verification code sent to the user
108
+
109
+ Returns:
110
+ True if verification was successful
111
+ """
112
+ return await self.auth.verify(verification_code)
113
+
114
+ async def logout(self) -> bool:
115
+ """Log out from the Eero API.
116
+
117
+ Returns:
118
+ True if logout was successful
119
+ """
120
+ return await self.auth.logout()
121
+
122
+ def set_preferred_network(self, network_id: str) -> None:
123
+ """Set the preferred network ID to use for requests.
124
+
125
+ Args:
126
+ network_id: ID of the network to use
127
+ """
128
+ self.auth.preferred_network_id = network_id
129
+
130
+ @property
131
+ def preferred_network_id(self) -> Optional[str]:
132
+ """Get the preferred network ID.
133
+
134
+ Returns:
135
+ Preferred network ID or None
136
+ """
137
+ return self.auth.preferred_network_id
eero/api/ac_compat.py ADDED
@@ -0,0 +1,49 @@
1
+ """AC Compatibility API for Eero."""
2
+
3
+ import logging
4
+ from typing import Any, Dict
5
+
6
+ from ..const import API_ENDPOINT
7
+ from ..exceptions import EeroAuthenticationException
8
+ from .auth import AuthAPI
9
+ from .base import AuthenticatedAPI
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ class ACCompatAPI(AuthenticatedAPI):
15
+ """AC Compatibility API for Eero."""
16
+
17
+ def __init__(self, auth_api: AuthAPI) -> None:
18
+ """Initialize the ACCompatAPI.
19
+
20
+ Args:
21
+ auth_api: Authentication API instance
22
+ """
23
+ super().__init__(auth_api, API_ENDPOINT)
24
+
25
+ async def get_ac_compat(self, network_id: str) -> Dict[str, Any]:
26
+ """Get AC compatibility information.
27
+
28
+ Args:
29
+ network_id: ID of the network to get AC compatibility info for
30
+
31
+ Returns:
32
+ AC compatibility data
33
+
34
+ Raises:
35
+ EeroAuthenticationException: If not authenticated
36
+ EeroAPIException: If the API returns an error
37
+ """
38
+ auth_token = await self._auth_api.get_auth_token()
39
+ if not auth_token:
40
+ raise EeroAuthenticationException("Not authenticated")
41
+
42
+ _LOGGER.debug(f"Getting AC compatibility for network {network_id}")
43
+
44
+ response = await self.get(
45
+ f"networks/{network_id}/ac_compat",
46
+ auth_token=auth_token,
47
+ )
48
+
49
+ return response.get("data", {})
eero/api/activity.py ADDED
@@ -0,0 +1,182 @@
1
+ """Activity API for Eero (Eero Plus feature)."""
2
+
3
+ import logging
4
+ from typing import Any, Dict, List
5
+
6
+ from ..const import API_ENDPOINT
7
+ from ..exceptions import EeroAuthenticationException
8
+ from .auth import AuthAPI
9
+ from .base import AuthenticatedAPI
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ class ActivityAPI(AuthenticatedAPI):
15
+ """Activity API for Eero.
16
+
17
+ Note: Activity data requires an active Eero Plus/Eero Secure subscription.
18
+ API calls may return empty data or errors for non-premium accounts.
19
+ """
20
+
21
+ def __init__(self, auth_api: AuthAPI) -> None:
22
+ """Initialize the ActivityAPI.
23
+
24
+ Args:
25
+ auth_api: Authentication API instance
26
+ """
27
+ super().__init__(auth_api, API_ENDPOINT)
28
+
29
+ async def get_activity(self, network_id: str) -> Dict[str, Any]:
30
+ """Get network activity summary.
31
+
32
+ Args:
33
+ network_id: ID of the network to get activity from
34
+
35
+ Returns:
36
+ Activity data including total usage, top clients, etc.
37
+
38
+ Raises:
39
+ EeroAuthenticationException: If not authenticated
40
+ EeroAPIException: If the API returns an error (may occur for non-premium)
41
+ """
42
+ auth_token = await self._auth_api.get_auth_token()
43
+ if not auth_token:
44
+ raise EeroAuthenticationException("Not authenticated")
45
+
46
+ _LOGGER.debug("Getting activity for network %s", network_id)
47
+
48
+ response = await self.get(
49
+ f"networks/{network_id}/activity",
50
+ auth_token=auth_token,
51
+ )
52
+
53
+ return response.get("data", {})
54
+
55
+ async def get_activity_clients(self, network_id: str) -> List[Dict[str, Any]]:
56
+ """Get per-client activity data.
57
+
58
+ Args:
59
+ network_id: ID of the network to get client activity from
60
+
61
+ Returns:
62
+ List of clients with their activity data
63
+
64
+ Raises:
65
+ EeroAuthenticationException: If not authenticated
66
+ EeroAPIException: If the API returns an error
67
+ """
68
+ auth_token = await self._auth_api.get_auth_token()
69
+ if not auth_token:
70
+ raise EeroAuthenticationException("Not authenticated")
71
+
72
+ _LOGGER.debug("Getting client activity for network %s", network_id)
73
+
74
+ response = await self.get(
75
+ f"networks/{network_id}/activity/clients",
76
+ auth_token=auth_token,
77
+ )
78
+
79
+ # Handle different response formats
80
+ data = response.get("data", [])
81
+ if isinstance(data, list):
82
+ return data
83
+ elif isinstance(data, dict) and "data" in data:
84
+ return data.get("data", [])
85
+ elif isinstance(data, dict) and "clients" in data:
86
+ return data.get("clients", [])
87
+ return []
88
+
89
+ async def get_activity_for_device(self, network_id: str, device_id: str) -> Dict[str, Any]:
90
+ """Get activity data for a specific device.
91
+
92
+ Args:
93
+ network_id: ID of the network
94
+ device_id: ID of the device to get activity for
95
+
96
+ Returns:
97
+ Activity data for the device
98
+
99
+ Raises:
100
+ EeroAuthenticationException: If not authenticated
101
+ EeroAPIException: If the API returns an error
102
+ """
103
+ auth_token = await self._auth_api.get_auth_token()
104
+ if not auth_token:
105
+ raise EeroAuthenticationException("Not authenticated")
106
+
107
+ _LOGGER.debug("Getting activity for device %s in network %s", device_id, network_id)
108
+
109
+ response = await self.get(
110
+ f"networks/{network_id}/activity/{device_id}",
111
+ auth_token=auth_token,
112
+ )
113
+
114
+ return response.get("data", {})
115
+
116
+ async def get_activity_history(
117
+ self,
118
+ network_id: str,
119
+ period: str = "day",
120
+ ) -> Dict[str, Any]:
121
+ """Get historical activity data.
122
+
123
+ Args:
124
+ network_id: ID of the network
125
+ period: Time period - "hour", "day", "week", or "month"
126
+
127
+ Returns:
128
+ Historical activity data
129
+
130
+ Raises:
131
+ EeroAuthenticationException: If not authenticated
132
+ EeroAPIException: If the API returns an error
133
+ """
134
+ auth_token = await self._auth_api.get_auth_token()
135
+ if not auth_token:
136
+ raise EeroAuthenticationException("Not authenticated")
137
+
138
+ valid_periods = ["hour", "day", "week", "month"]
139
+ if period not in valid_periods:
140
+ _LOGGER.warning("Invalid period '%s', defaulting to 'day'", period)
141
+ period = "day"
142
+
143
+ _LOGGER.debug("Getting activity history for network %s (period: %s)", network_id, period)
144
+
145
+ response = await self.get(
146
+ f"networks/{network_id}/activity/history",
147
+ auth_token=auth_token,
148
+ params={"period": period},
149
+ )
150
+
151
+ return response.get("data", {})
152
+
153
+ async def get_activity_categories(self, network_id: str) -> List[Dict[str, Any]]:
154
+ """Get activity data grouped by category.
155
+
156
+ Args:
157
+ network_id: ID of the network
158
+
159
+ Returns:
160
+ Activity data grouped by category (streaming, gaming, social, etc.)
161
+
162
+ Raises:
163
+ EeroAuthenticationException: If not authenticated
164
+ EeroAPIException: If the API returns an error
165
+ """
166
+ auth_token = await self._auth_api.get_auth_token()
167
+ if not auth_token:
168
+ raise EeroAuthenticationException("Not authenticated")
169
+
170
+ _LOGGER.debug("Getting activity categories for network %s", network_id)
171
+
172
+ response = await self.get(
173
+ f"networks/{network_id}/activity/categories",
174
+ auth_token=auth_token,
175
+ )
176
+
177
+ data = response.get("data", [])
178
+ if isinstance(data, list):
179
+ return data
180
+ elif isinstance(data, dict) and "categories" in data:
181
+ return data.get("categories", [])
182
+ return []