bbox-api 0.1.0__tar.gz

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.
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ .idea/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ htmlcov/
12
+ .coverage
bbox_api-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rettelx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.5
2
+ Name: bbox-api
3
+ Version: 0.1.0
4
+ Summary: Async Python client for the Bouygues Telecom Bbox router API
5
+ Project-URL: Homepage, https://github.com/xavier/bbox-api
6
+ Project-URL: Repository, https://github.com/xavier/bbox-api
7
+ Project-URL: Issues, https://github.com/xavier/bbox-api/issues
8
+ Project-URL: Documentation, https://github.com/xavier/bbox-api#readme
9
+ Author: rettelx
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: aiohttp,api,async,bbox,bouygues,bouygues-telecom,gateway,router
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: aiohttp>=3.9
27
+ Provides-Extra: dev
28
+ Requires-Dist: aiohttp<3.14,>=3.9; extra == 'dev'
29
+ Requires-Dist: aioresponses>=0.7; extra == 'dev'
30
+ Requires-Dist: mypy; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=1; extra == 'dev'
32
+ Requires-Dist: pytest>=8; extra == 'dev'
33
+ Requires-Dist: ruff; extra == 'dev'
34
+ Provides-Extra: test
35
+ Requires-Dist: aiohttp<3.14,>=3.9; extra == 'test'
36
+ Requires-Dist: aioresponses>=0.7; extra == 'test'
37
+ Requires-Dist: pytest-asyncio>=1; extra == 'test'
38
+ Requires-Dist: pytest>=8; extra == 'test'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # bbox-api
42
+
43
+ Async client for the **Bouygues Telecom Bbox router API** (`/api/v1`), for any
44
+ asyncio app. Python >= 3.11, MIT, single dependency (`aiohttp`), fully typed
45
+ (`py.typed`, mypy-clean) with fault-tolerant dataclass models (unknown or
46
+ malformed payload keys never crash parsing; unknown keys stay in `.raw`).
47
+
48
+ - **Local**: `BboxClient(pw)` → `http://bbox.lan/api/v1` (also `192.168.1.1` or
49
+ `mabbox.bytel.fr` with `use_tls=True` — that name resolves only on the LAN,
50
+ the box hijacks DNS for it). **Remote**: `BboxClient.remote(pw, wan_ip)` →
51
+ `https://<wan-ip>/api/v1` ("remote access" enabled on the box; the WAN IP is
52
+ refused from the LAN itself).
53
+ - **Auth is automatic**: admin password → session cookie + cached `btoken`,
54
+ re-auth on 401, retries on transient errors.
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install bbox-api
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ```python
65
+ import asyncio
66
+ from bbox_api import BboxClient
67
+
68
+
69
+ async def main():
70
+ async with BboxClient("admin-password") as client: # local: bbox.lan
71
+ device = await client.get_device() # model, firmware, uptime
72
+ stats = await client.get_wan_ip_stats() # rx/tx bandwidth_mbps
73
+ hosts = await client.get_hosts() # connected devices
74
+ await client.set_wireless(False) # all main Wi-Fi bands off
75
+
76
+
77
+ asyncio.run(main())
78
+ ```
79
+
80
+ Any endpoint not wrapped by a typed method: `await client.raw_request("alerts")`.
81
+ To share your own `aiohttp.ClientSession`, pass `session=` — the client then
82
+ never closes it.
83
+
84
+ ## Errors
85
+
86
+ All inherit `BboxApiError`: `BboxInvalidCredentialsError`, `BboxSessionExpiredError`, `BboxRateLimitError`, `BboxNotFoundError`, `BboxConnectionError`, `BboxTimeoutError`.
87
+
88
+ ## Verified endpoints (live-tested on a F@st5688b, fw 25.1.22)
89
+
90
+ GET endpoints returning HTTP 200, grouped by area:
91
+
92
+ - **device**: `device`, `device/cpu`, `device/mem`, `device/summary`, `device/log`, `device/led`
93
+ - **hosts**: `hosts`, `hosts/me`, `alerts`
94
+ - **wan**: `wan/ip`, `wan/ip/stats`, `wan/ftth/stats`, `wan/diags`, `cpl`
95
+ - **wireless**: `wireless`, `wireless/24`, `wireless/5`, `wireless/6`, `wireless/guest`,
96
+ `wireless/24/stats`, `wireless/5/stats`, `wireless/6/stats`, `wireless/wps`,
97
+ `wireless/repeater`, `wireless/scheduler`
98
+ - **lan / misc**: `summary`, `lan/ip`, `lan/stats`, `iptv`, `services`, `speedtest`,
99
+ `parentalcontrol`, `voip`, `voip/fullcalllog/<line-id>` (line id from `GET /voip`,
100
+ e.g. `voip/fullcalllog/1`)
101
+
102
+ GET endpoints returning 404 on this model/firmware (they raise `BboxNotFoundError`):
103
+
104
+ - `device/optimization`, `wan/ftth`, `wan/xdsl`, `wan/xdsl/stats`, `wan/cable`
105
+ (this is a FTTH box), `lan/ip6`, `ddns`, `remote`, `voip/voicemail`,
106
+ `voip/callforward`, `voip/fullcalllog` without a line id
107
+
108
+ Writes verified (PUT/POST/DELETE with `btoken`):
109
+
110
+ - `PUT /wireless` + `radio.enable=0/1` — toggles all main bands (2.4/5/6 GHz) at once
111
+ - `PUT /wireless/guestenable` + `enable=0/1` — guest Wi-Fi
112
+ - `POST` / `DELETE /wireless/wps` — start/stop a WPS session
113
+
114
+ Behavior notes from live testing:
115
+
116
+ - `/hosts` returns a **list of blocks**: the first is the main LAN, the following
117
+ ones are e.g. the guest network (entries flagged `guest=1`, 10.0.0.x subnet).
118
+ The guest block stays present even when guest Wi-Fi is off (its hosts just show
119
+ `active=False`). `get_hosts()` parses all blocks and excludes guests unless
120
+ `include_guests=True`; `get_guests()` returns only guest hosts.
121
+
122
+ Security warning: `GET /wireless` returns the **Wi-Fi passphrase in clear text**
123
+ (`raw["bands"]["24"]["security"]["passphrase"]`). Never expose a model's `raw`
124
+ dict in logs or API responses.
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ python -m venv .venv && .venv/Scripts/pip install -e ".[dev]"
130
+ .venv/Scripts/python -m pytest # 44 tests, mocked API (aiohttp<3.14: aioresponses limit)
131
+ .venv/Scripts/ruff check .
132
+ .venv/Scripts/python -m mypy
133
+ ```
134
+
135
+ CI/CD (`.github/workflows/`): `ci.yml` runs pytest on Python 3.11–3.14 plus
136
+ ruff and mypy on every push/PR; `release.yml` builds the wheel/sdist with
137
+ hatchling and publishes to PyPI on `v*` tags via trusted publishing (OIDC —
138
+ configure the `bbox-api` project on PyPI with this repo as trusted publisher,
139
+ no API token needed).
140
+
141
+ ## License
142
+
143
+ MIT
@@ -0,0 +1,103 @@
1
+ # bbox-api
2
+
3
+ Async client for the **Bouygues Telecom Bbox router API** (`/api/v1`), for any
4
+ asyncio app. Python >= 3.11, MIT, single dependency (`aiohttp`), fully typed
5
+ (`py.typed`, mypy-clean) with fault-tolerant dataclass models (unknown or
6
+ malformed payload keys never crash parsing; unknown keys stay in `.raw`).
7
+
8
+ - **Local**: `BboxClient(pw)` → `http://bbox.lan/api/v1` (also `192.168.1.1` or
9
+ `mabbox.bytel.fr` with `use_tls=True` — that name resolves only on the LAN,
10
+ the box hijacks DNS for it). **Remote**: `BboxClient.remote(pw, wan_ip)` →
11
+ `https://<wan-ip>/api/v1` ("remote access" enabled on the box; the WAN IP is
12
+ refused from the LAN itself).
13
+ - **Auth is automatic**: admin password → session cookie + cached `btoken`,
14
+ re-auth on 401, retries on transient errors.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install bbox-api
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```python
25
+ import asyncio
26
+ from bbox_api import BboxClient
27
+
28
+
29
+ async def main():
30
+ async with BboxClient("admin-password") as client: # local: bbox.lan
31
+ device = await client.get_device() # model, firmware, uptime
32
+ stats = await client.get_wan_ip_stats() # rx/tx bandwidth_mbps
33
+ hosts = await client.get_hosts() # connected devices
34
+ await client.set_wireless(False) # all main Wi-Fi bands off
35
+
36
+
37
+ asyncio.run(main())
38
+ ```
39
+
40
+ Any endpoint not wrapped by a typed method: `await client.raw_request("alerts")`.
41
+ To share your own `aiohttp.ClientSession`, pass `session=` — the client then
42
+ never closes it.
43
+
44
+ ## Errors
45
+
46
+ All inherit `BboxApiError`: `BboxInvalidCredentialsError`, `BboxSessionExpiredError`, `BboxRateLimitError`, `BboxNotFoundError`, `BboxConnectionError`, `BboxTimeoutError`.
47
+
48
+ ## Verified endpoints (live-tested on a F@st5688b, fw 25.1.22)
49
+
50
+ GET endpoints returning HTTP 200, grouped by area:
51
+
52
+ - **device**: `device`, `device/cpu`, `device/mem`, `device/summary`, `device/log`, `device/led`
53
+ - **hosts**: `hosts`, `hosts/me`, `alerts`
54
+ - **wan**: `wan/ip`, `wan/ip/stats`, `wan/ftth/stats`, `wan/diags`, `cpl`
55
+ - **wireless**: `wireless`, `wireless/24`, `wireless/5`, `wireless/6`, `wireless/guest`,
56
+ `wireless/24/stats`, `wireless/5/stats`, `wireless/6/stats`, `wireless/wps`,
57
+ `wireless/repeater`, `wireless/scheduler`
58
+ - **lan / misc**: `summary`, `lan/ip`, `lan/stats`, `iptv`, `services`, `speedtest`,
59
+ `parentalcontrol`, `voip`, `voip/fullcalllog/<line-id>` (line id from `GET /voip`,
60
+ e.g. `voip/fullcalllog/1`)
61
+
62
+ GET endpoints returning 404 on this model/firmware (they raise `BboxNotFoundError`):
63
+
64
+ - `device/optimization`, `wan/ftth`, `wan/xdsl`, `wan/xdsl/stats`, `wan/cable`
65
+ (this is a FTTH box), `lan/ip6`, `ddns`, `remote`, `voip/voicemail`,
66
+ `voip/callforward`, `voip/fullcalllog` without a line id
67
+
68
+ Writes verified (PUT/POST/DELETE with `btoken`):
69
+
70
+ - `PUT /wireless` + `radio.enable=0/1` — toggles all main bands (2.4/5/6 GHz) at once
71
+ - `PUT /wireless/guestenable` + `enable=0/1` — guest Wi-Fi
72
+ - `POST` / `DELETE /wireless/wps` — start/stop a WPS session
73
+
74
+ Behavior notes from live testing:
75
+
76
+ - `/hosts` returns a **list of blocks**: the first is the main LAN, the following
77
+ ones are e.g. the guest network (entries flagged `guest=1`, 10.0.0.x subnet).
78
+ The guest block stays present even when guest Wi-Fi is off (its hosts just show
79
+ `active=False`). `get_hosts()` parses all blocks and excludes guests unless
80
+ `include_guests=True`; `get_guests()` returns only guest hosts.
81
+
82
+ Security warning: `GET /wireless` returns the **Wi-Fi passphrase in clear text**
83
+ (`raw["bands"]["24"]["security"]["passphrase"]`). Never expose a model's `raw`
84
+ dict in logs or API responses.
85
+
86
+ ## Development
87
+
88
+ ```bash
89
+ python -m venv .venv && .venv/Scripts/pip install -e ".[dev]"
90
+ .venv/Scripts/python -m pytest # 44 tests, mocked API (aiohttp<3.14: aioresponses limit)
91
+ .venv/Scripts/ruff check .
92
+ .venv/Scripts/python -m mypy
93
+ ```
94
+
95
+ CI/CD (`.github/workflows/`): `ci.yml` runs pytest on Python 3.11–3.14 plus
96
+ ruff and mypy on every push/PR; `release.yml` builds the wheel/sdist with
97
+ hatchling and publishes to PyPI on `v*` tags via trusted publishing (OIDC —
98
+ configure the `bbox-api` project on PyPI with this repo as trusted publisher,
99
+ no API token needed).
100
+
101
+ ## License
102
+
103
+ MIT
@@ -0,0 +1,89 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.26"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "bbox-api"
7
+ version = "0.1.0"
8
+ description = "Async Python client for the Bouygues Telecom Bbox router API"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.11"
13
+ authors = [{ name = "rettelx" }]
14
+ keywords = [
15
+ "bbox",
16
+ "bouygues",
17
+ "bouygues-telecom",
18
+ "router",
19
+ "gateway",
20
+ "api",
21
+ "async",
22
+ "aiohttp",
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 3 - Alpha",
26
+ "Intended Audience :: Developers",
27
+ "Framework :: AsyncIO",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Programming Language :: Python :: 3.14",
35
+ "Topic :: Software Development :: Libraries :: Python Modules",
36
+ "Typing :: Typed",
37
+ ]
38
+ dependencies = ["aiohttp>=3.9"]
39
+
40
+ [project.optional-dependencies]
41
+ test = [
42
+ "pytest>=8",
43
+ "pytest-asyncio>=1",
44
+ "aioresponses>=0.7",
45
+ # aioresponses 0.7.x does not support aiohttp 3.14 yet (ClientResponse
46
+ # gained a required stream_writer arg); CI pins aiohttp<3.14 for tests.
47
+ "aiohttp>=3.9,<3.14",
48
+ ]
49
+ dev = [
50
+ "bbox-api[test]",
51
+ "ruff",
52
+ "mypy",
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/xavier/bbox-api"
57
+ Repository = "https://github.com/xavier/bbox-api"
58
+ Issues = "https://github.com/xavier/bbox-api/issues"
59
+ Documentation = "https://github.com/xavier/bbox-api#readme"
60
+
61
+ [tool.hatch.build.targets.wheel]
62
+ packages = ["src/bbox_api"]
63
+
64
+ [tool.hatch.build.targets.sdist]
65
+ include = ["src/bbox_api", "tests", "README.md", "LICENSE"]
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ asyncio_mode = "auto"
70
+ asyncio_default_fixture_loop_scope = "function"
71
+ addopts = "--strict-markers"
72
+
73
+ [tool.ruff]
74
+ line-length = 100
75
+ target-version = "py311"
76
+
77
+ [tool.ruff.lint]
78
+ select = ["E", "W", "F", "I", "B", "C4", "UP", "SIM", "RUF"]
79
+ ignore = ["SIM108"]
80
+
81
+ [tool.ruff.lint.isort]
82
+ known-first-party = ["bbox_api"]
83
+
84
+ [tool.mypy]
85
+ python_version = "3.11"
86
+ files = ["src/bbox_api"]
87
+ warn_unused_ignores = true
88
+ warn_redundant_casts = true
89
+ disallow_untyped_defs = true
@@ -0,0 +1,60 @@
1
+ """Async Python client for the Bouygues Telecom Bbox router API."""
2
+
3
+ from .client import BboxClient
4
+ from .exceptions import (
5
+ BboxApiError,
6
+ BboxAuthenticationError,
7
+ BboxConnectionError,
8
+ BboxInvalidCredentialsError,
9
+ BboxNotFoundError,
10
+ BboxRateLimitError,
11
+ BboxSessionExpiredError,
12
+ BboxTimeoutError,
13
+ )
14
+ from .models import (
15
+ WANIP,
16
+ BboxModel,
17
+ ConnectionFlags,
18
+ DeviceInfo,
19
+ Display,
20
+ EthernetInfo,
21
+ FirmwareVersion,
22
+ Host,
23
+ IPv6Address,
24
+ WANIPStats,
25
+ WANStats,
26
+ Wireless,
27
+ WirelessBand,
28
+ WirelessInfo,
29
+ WirelessRadio,
30
+ )
31
+
32
+ __version__ = "0.1.0"
33
+
34
+ __all__ = [
35
+ "WANIP",
36
+ "BboxApiError",
37
+ "BboxAuthenticationError",
38
+ "BboxClient",
39
+ "BboxConnectionError",
40
+ "BboxInvalidCredentialsError",
41
+ "BboxModel",
42
+ "BboxNotFoundError",
43
+ "BboxRateLimitError",
44
+ "BboxSessionExpiredError",
45
+ "BboxTimeoutError",
46
+ "ConnectionFlags",
47
+ "DeviceInfo",
48
+ "Display",
49
+ "EthernetInfo",
50
+ "FirmwareVersion",
51
+ "Host",
52
+ "IPv6Address",
53
+ "WANIPStats",
54
+ "WANStats",
55
+ "Wireless",
56
+ "WirelessBand",
57
+ "WirelessInfo",
58
+ "WirelessRadio",
59
+ "__version__",
60
+ ]