eeroctl 1.7.1__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.
- eeroctl/__init__.py +19 -0
- eeroctl/commands/__init__.py +32 -0
- eeroctl/commands/activity.py +237 -0
- eeroctl/commands/auth.py +471 -0
- eeroctl/commands/completion.py +142 -0
- eeroctl/commands/device.py +492 -0
- eeroctl/commands/eero/__init__.py +12 -0
- eeroctl/commands/eero/base.py +224 -0
- eeroctl/commands/eero/led.py +154 -0
- eeroctl/commands/eero/nightlight.py +235 -0
- eeroctl/commands/eero/updates.py +82 -0
- eeroctl/commands/network/__init__.py +18 -0
- eeroctl/commands/network/advanced.py +191 -0
- eeroctl/commands/network/backup.py +162 -0
- eeroctl/commands/network/base.py +331 -0
- eeroctl/commands/network/dhcp.py +118 -0
- eeroctl/commands/network/dns.py +197 -0
- eeroctl/commands/network/forwards.py +115 -0
- eeroctl/commands/network/guest.py +162 -0
- eeroctl/commands/network/security.py +162 -0
- eeroctl/commands/network/speedtest.py +99 -0
- eeroctl/commands/network/sqm.py +194 -0
- eeroctl/commands/profile.py +671 -0
- eeroctl/commands/troubleshoot.py +317 -0
- eeroctl/context.py +254 -0
- eeroctl/errors.py +156 -0
- eeroctl/exit_codes.py +68 -0
- eeroctl/formatting/__init__.py +90 -0
- eeroctl/formatting/base.py +181 -0
- eeroctl/formatting/device.py +430 -0
- eeroctl/formatting/eero.py +591 -0
- eeroctl/formatting/misc.py +87 -0
- eeroctl/formatting/network.py +659 -0
- eeroctl/formatting/profile.py +443 -0
- eeroctl/main.py +161 -0
- eeroctl/options.py +429 -0
- eeroctl/output.py +739 -0
- eeroctl/safety.py +259 -0
- eeroctl/utils.py +181 -0
- eeroctl-1.7.1.dist-info/METADATA +115 -0
- eeroctl-1.7.1.dist-info/RECORD +45 -0
- eeroctl-1.7.1.dist-info/WHEEL +5 -0
- eeroctl-1.7.1.dist-info/entry_points.txt +3 -0
- eeroctl-1.7.1.dist-info/licenses/LICENSE +21 -0
- eeroctl-1.7.1.dist-info/top_level.txt +1 -0
eeroctl/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Command-line interface for Eero client.
|
|
2
|
+
|
|
3
|
+
This package provides the CLI for managing Eero networks.
|
|
4
|
+
|
|
5
|
+
Entry point: eeroctl.main:cli
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .main import cli, main
|
|
9
|
+
|
|
10
|
+
__version__ = "1.7.1"
|
|
11
|
+
__version_info__ = tuple(int(x) for x in __version__.split(".")[:3])
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_version() -> str:
|
|
15
|
+
"""Return the current version of eeroctl."""
|
|
16
|
+
return __version__
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = ["cli", "main", "__version__", "__version_info__", "get_version"]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""New command structure for the Eero CLI.
|
|
2
|
+
|
|
3
|
+
This package contains the new noun-first command tree:
|
|
4
|
+
- auth: Authentication management
|
|
5
|
+
- network: Network configuration and settings
|
|
6
|
+
- eero: Mesh node management
|
|
7
|
+
- device: Connected device management
|
|
8
|
+
- profile: Profile/parental controls management
|
|
9
|
+
- activity: Network activity data (Eero Plus)
|
|
10
|
+
- troubleshoot: Diagnostics and troubleshooting
|
|
11
|
+
- completion: Shell completion
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .activity import activity_group
|
|
15
|
+
from .auth import auth_group
|
|
16
|
+
from .completion import completion_group
|
|
17
|
+
from .device import device_group
|
|
18
|
+
from .eero import eero_group
|
|
19
|
+
from .network import network_group
|
|
20
|
+
from .profile import profile_group
|
|
21
|
+
from .troubleshoot import troubleshoot_group
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"auth_group",
|
|
25
|
+
"network_group",
|
|
26
|
+
"eero_group",
|
|
27
|
+
"device_group",
|
|
28
|
+
"profile_group",
|
|
29
|
+
"activity_group",
|
|
30
|
+
"troubleshoot_group",
|
|
31
|
+
"completion_group",
|
|
32
|
+
]
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Activity commands for the Eero CLI (Eero Plus feature).
|
|
2
|
+
|
|
3
|
+
Commands:
|
|
4
|
+
- eero activity summary: Network activity summary
|
|
5
|
+
- eero activity clients: Per-client activity
|
|
6
|
+
- eero activity history: Historical activity
|
|
7
|
+
- eero activity categories: Activity by category
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from eero import EeroClient
|
|
15
|
+
from rich.panel import Panel
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
|
|
18
|
+
from ..context import ensure_cli_context
|
|
19
|
+
from ..errors import is_premium_error
|
|
20
|
+
from ..exit_codes import ExitCode
|
|
21
|
+
from ..options import apply_options, network_option, output_option
|
|
22
|
+
from ..utils import with_client
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _format_bytes(bytes_val: int) -> str:
|
|
26
|
+
"""Format bytes into human-readable format."""
|
|
27
|
+
if bytes_val < 1024:
|
|
28
|
+
return f"{bytes_val} B"
|
|
29
|
+
elif bytes_val < 1024 * 1024:
|
|
30
|
+
return f"{bytes_val / 1024:.1f} KB"
|
|
31
|
+
elif bytes_val < 1024 * 1024 * 1024:
|
|
32
|
+
return f"{bytes_val / (1024 * 1024):.1f} MB"
|
|
33
|
+
else:
|
|
34
|
+
return f"{bytes_val / (1024 * 1024 * 1024):.2f} GB"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.group(name="activity")
|
|
38
|
+
@click.pass_context
|
|
39
|
+
def activity_group(ctx: click.Context) -> None:
|
|
40
|
+
"""View network activity data (Eero Plus feature).
|
|
41
|
+
|
|
42
|
+
\b
|
|
43
|
+
Commands:
|
|
44
|
+
summary - Network activity summary
|
|
45
|
+
clients - Per-client activity
|
|
46
|
+
history - Historical activity
|
|
47
|
+
categories - Activity by category
|
|
48
|
+
|
|
49
|
+
\b
|
|
50
|
+
Note: Requires an active Eero Plus subscription.
|
|
51
|
+
|
|
52
|
+
\b
|
|
53
|
+
Examples:
|
|
54
|
+
eero activity summary
|
|
55
|
+
eero activity clients
|
|
56
|
+
eero activity history --period week
|
|
57
|
+
"""
|
|
58
|
+
ensure_cli_context(ctx)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@activity_group.command(name="summary")
|
|
62
|
+
@output_option
|
|
63
|
+
@network_option
|
|
64
|
+
@click.pass_context
|
|
65
|
+
@with_client
|
|
66
|
+
async def activity_summary(
|
|
67
|
+
ctx: click.Context, client: EeroClient, output: Optional[str], network_id: Optional[str]
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Show network activity summary."""
|
|
70
|
+
cli_ctx = apply_options(ctx, output=output, network_id=network_id)
|
|
71
|
+
console = cli_ctx.console
|
|
72
|
+
|
|
73
|
+
with cli_ctx.status("Getting network activity..."):
|
|
74
|
+
try:
|
|
75
|
+
activity_data = await client.get_activity(cli_ctx.network_id)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
if is_premium_error(e):
|
|
78
|
+
console.print("[yellow]This feature requires Eero Plus subscription[/yellow]")
|
|
79
|
+
sys.exit(ExitCode.PREMIUM_REQUIRED)
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
if cli_ctx.is_structured_output():
|
|
83
|
+
cli_ctx.render_structured(activity_data, "eero.activity.summary/v1")
|
|
84
|
+
else:
|
|
85
|
+
upload = activity_data.get("upload_bytes", 0)
|
|
86
|
+
download = activity_data.get("download_bytes", 0)
|
|
87
|
+
total = upload + download
|
|
88
|
+
|
|
89
|
+
content = (
|
|
90
|
+
f"[bold cyan]Download:[/bold cyan] {_format_bytes(download)}\n"
|
|
91
|
+
f"[bold cyan]Upload:[/bold cyan] {_format_bytes(upload)}\n"
|
|
92
|
+
f"[bold cyan]Total:[/bold cyan] {_format_bytes(total)}"
|
|
93
|
+
)
|
|
94
|
+
console.print(Panel(content, title="Network Activity Summary", border_style="blue"))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@activity_group.command(name="clients")
|
|
98
|
+
@output_option
|
|
99
|
+
@network_option
|
|
100
|
+
@click.pass_context
|
|
101
|
+
@with_client
|
|
102
|
+
async def activity_clients(
|
|
103
|
+
ctx: click.Context, client: EeroClient, output: Optional[str], network_id: Optional[str]
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Show per-client activity data."""
|
|
106
|
+
cli_ctx = apply_options(ctx, output=output, network_id=network_id)
|
|
107
|
+
console = cli_ctx.console
|
|
108
|
+
|
|
109
|
+
with cli_ctx.status("Getting client activity..."):
|
|
110
|
+
try:
|
|
111
|
+
clients_data = await client.get_activity_clients(cli_ctx.network_id)
|
|
112
|
+
except Exception as e:
|
|
113
|
+
if is_premium_error(e):
|
|
114
|
+
console.print("[yellow]This feature requires Eero Plus subscription[/yellow]")
|
|
115
|
+
sys.exit(ExitCode.PREMIUM_REQUIRED)
|
|
116
|
+
raise
|
|
117
|
+
|
|
118
|
+
if cli_ctx.is_structured_output():
|
|
119
|
+
cli_ctx.render_structured(clients_data, "eero.activity.clients/v1")
|
|
120
|
+
else:
|
|
121
|
+
if not clients_data:
|
|
122
|
+
console.print("[yellow]No client activity data available[/yellow]")
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
table = Table(title="Client Activity")
|
|
126
|
+
table.add_column("Device", style="cyan")
|
|
127
|
+
table.add_column("Download", justify="right")
|
|
128
|
+
table.add_column("Upload", justify="right")
|
|
129
|
+
table.add_column("Total", justify="right")
|
|
130
|
+
|
|
131
|
+
for client_info in clients_data:
|
|
132
|
+
name = (
|
|
133
|
+
client_info.get("display_name")
|
|
134
|
+
or client_info.get("hostname")
|
|
135
|
+
or client_info.get("mac", "Unknown")
|
|
136
|
+
)
|
|
137
|
+
download = client_info.get("download_bytes", 0)
|
|
138
|
+
upload = client_info.get("upload_bytes", 0)
|
|
139
|
+
total = download + upload
|
|
140
|
+
|
|
141
|
+
table.add_row(
|
|
142
|
+
name, _format_bytes(download), _format_bytes(upload), _format_bytes(total)
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
console.print(table)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@activity_group.command(name="history")
|
|
149
|
+
@click.option(
|
|
150
|
+
"--period",
|
|
151
|
+
type=click.Choice(["hour", "day", "week", "month"]),
|
|
152
|
+
default="day",
|
|
153
|
+
help="Time period (default: day)",
|
|
154
|
+
)
|
|
155
|
+
@output_option
|
|
156
|
+
@network_option
|
|
157
|
+
@click.pass_context
|
|
158
|
+
@with_client
|
|
159
|
+
async def activity_history(
|
|
160
|
+
ctx: click.Context,
|
|
161
|
+
client: EeroClient,
|
|
162
|
+
period: str,
|
|
163
|
+
output: Optional[str],
|
|
164
|
+
network_id: Optional[str],
|
|
165
|
+
) -> None:
|
|
166
|
+
"""Show historical activity data.
|
|
167
|
+
|
|
168
|
+
\b
|
|
169
|
+
Options:
|
|
170
|
+
--period Time period: hour, day, week, month
|
|
171
|
+
"""
|
|
172
|
+
cli_ctx = apply_options(ctx, output=output, network_id=network_id)
|
|
173
|
+
console = cli_ctx.console
|
|
174
|
+
|
|
175
|
+
with cli_ctx.status(f"Getting activity history ({period})..."):
|
|
176
|
+
try:
|
|
177
|
+
history_data = await client.get_activity_history(cli_ctx.network_id, period)
|
|
178
|
+
except Exception as e:
|
|
179
|
+
if is_premium_error(e):
|
|
180
|
+
console.print("[yellow]This feature requires Eero Plus subscription[/yellow]")
|
|
181
|
+
sys.exit(ExitCode.PREMIUM_REQUIRED)
|
|
182
|
+
raise
|
|
183
|
+
|
|
184
|
+
if cli_ctx.is_structured_output():
|
|
185
|
+
cli_ctx.render_structured(history_data, "eero.activity.history/v1")
|
|
186
|
+
else:
|
|
187
|
+
total_download = history_data.get("total_download_bytes", 0)
|
|
188
|
+
total_upload = history_data.get("total_upload_bytes", 0)
|
|
189
|
+
data_points = history_data.get("data_points", [])
|
|
190
|
+
|
|
191
|
+
content = (
|
|
192
|
+
f"[bold]Period:[/bold] {period}\n"
|
|
193
|
+
f"[bold cyan]Total Download:[/bold cyan] {_format_bytes(total_download)}\n"
|
|
194
|
+
f"[bold cyan]Total Upload:[/bold cyan] {_format_bytes(total_upload)}\n"
|
|
195
|
+
f"[bold]Data Points:[/bold] {len(data_points)}"
|
|
196
|
+
)
|
|
197
|
+
console.print(Panel(content, title=f"Activity History ({period})", border_style="blue"))
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@activity_group.command(name="categories")
|
|
201
|
+
@output_option
|
|
202
|
+
@network_option
|
|
203
|
+
@click.pass_context
|
|
204
|
+
@with_client
|
|
205
|
+
async def activity_categories(
|
|
206
|
+
ctx: click.Context, client: EeroClient, output: Optional[str], network_id: Optional[str]
|
|
207
|
+
) -> None:
|
|
208
|
+
"""Show activity grouped by category."""
|
|
209
|
+
cli_ctx = apply_options(ctx, output=output, network_id=network_id)
|
|
210
|
+
console = cli_ctx.console
|
|
211
|
+
|
|
212
|
+
with cli_ctx.status("Getting activity categories..."):
|
|
213
|
+
try:
|
|
214
|
+
categories_data = await client.get_activity_categories(cli_ctx.network_id)
|
|
215
|
+
except Exception as e:
|
|
216
|
+
if is_premium_error(e):
|
|
217
|
+
console.print("[yellow]This feature requires Eero Plus subscription[/yellow]")
|
|
218
|
+
sys.exit(ExitCode.PREMIUM_REQUIRED)
|
|
219
|
+
raise
|
|
220
|
+
|
|
221
|
+
if cli_ctx.is_structured_output():
|
|
222
|
+
cli_ctx.render_structured(categories_data, "eero.activity.categories/v1")
|
|
223
|
+
else:
|
|
224
|
+
if not categories_data:
|
|
225
|
+
console.print("[yellow]No category data available[/yellow]")
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
table = Table(title="Activity by Category")
|
|
229
|
+
table.add_column("Category", style="cyan")
|
|
230
|
+
table.add_column("Usage", justify="right")
|
|
231
|
+
|
|
232
|
+
for category in categories_data:
|
|
233
|
+
name = category.get("name", "Unknown")
|
|
234
|
+
usage = category.get("bytes", 0)
|
|
235
|
+
table.add_row(name, _format_bytes(usage))
|
|
236
|
+
|
|
237
|
+
console.print(table)
|