### Install sagemcom_api Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Install the library using pip or uv. ```bash pip install sagemcom_api # or uv add sagemcom_api ``` -------------------------------- ### Install sagemcom-api Source: https://github.com/imicknl/python-sagemcom-api/blob/main/README.md Install the sagemcom_api package using pip. Ensure you have Python 3.11+. ```bash pip install sagemcom_api ``` -------------------------------- ### Quickstart Python Script for Sagemcom API Source: https://github.com/imicknl/python-sagemcom-api/blob/main/README.md This script demonstrates basic usage of the SagemcomClient for logging in, retrieving device information, listing connected hosts, and setting a parameter via XPath. Ensure you replace placeholder values for HOST, USERNAME, and PASSWORD. It supports both SHA512 and MD5 encryption methods. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import NonWritableParameterException HOST = "" USERNAME = "" PASSWORD = "" ENCRYPTION_METHOD = EncryptionMethod.SHA512 # or EncryptionMethod.MD5 VALIDATE_SSL_CERT = True async def main() -> None: async with SagemcomClient(HOST, USERNAME, PASSWORD, ENCRYPTION_METHOD, verify_ssl=VALIDATE_SSL_CERT) as client: try: await client.login() except Exception as exception: # pylint: disable=broad-except print(exception) return # Print device information of Sagemcom F@st router device_info = await client.get_device_info() print(f"{device_info.id} {device_info.model_name}") # Print connected devices devices = await client.get_hosts() for device in devices: if device.active: print(f"{device.id} - {device.name}") # Retrieve values via XPath notation, output is a dict custom_command_output = await client.get_value_by_xpath("Device/UserInterface/AdvancedMode") print(custom_command_output) # Set value via XPath notation and catch specific errors try: custom_command_output = await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") except NonWritableParameterException as exception: # pylint: disable=broad-except print("Not allowed to set AdvancedMode parameter on your device.") return print(custom_command_output) asyncio.run(main()) ``` -------------------------------- ### Fixture Usage for Mocking Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Example of using fixtures like `mock_session_factory` and `login_success_response` to set up mocked API responses for testing. Requires `pytest` and `pytest-asyncio`. ```python @pytest.mark.asyncio async def test_example(mock_session_factory, login_success_response): mock_session = mock_session_factory([login_success_response]) client = SagemcomClient("192.168.1.1", "admin", "password", EncryptionMethod.MD5, session=mock_session) # Test implementation... ``` -------------------------------- ### Auto-detect Encryption Method Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Use this method during initial setup when the correct authentication method is unknown. It iterates through MD5, SHA512, and MD5_NONCE, returning the first successful one. Returns None if no method works. ```python import asyncio from sagemcom_api.client import SagemcomClient async def main(): # Pass no authentication_method so get_encryption_method can probe all options client = SagemcomClient("192.168.1.1", "admin", "mypassword") method = await client.get_encryption_method() if method: print(f"Use EncryptionMethod.{method.name} for this router") else: print("No compatible encryption method found — check host and credentials") await client.close() asyncio.run(main()) ``` -------------------------------- ### Retrieve Values using XPath with Sagemcom API Source: https://github.com/imicknl/python-sagemcom-api/blob/main/README.md This example demonstrates how to retrieve any value from the Sagemcom router using its XPath. It includes basic exception handling for cases where the XPath might not exist or other errors occur during the request. ```python try: result = await client.get_value_by_xpath("Device/DeviceSummary") except Exception as exception: print(exception) ``` -------------------------------- ### Run Speed Test and Get Results Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Triggers a speed test on the router and retrieves historical results. Ensure a delay after triggering the test to allow it to complete before fetching results. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() # Kick off a speed test (returns immediately; the router runs it in the background) await client.run_speed_test(block_traffic=False) # Wait a moment, then retrieve results await asyncio.sleep(30) results = await client.get_speed_test_results() for r in results: print(r) # e.g. timestamp: 2024-03-15 10:22:01, latency: 12ms, upload: 48.3, download: 195.7 asyncio.run(main()) ``` -------------------------------- ### get_encryption_method() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Automatically detects and returns the correct encryption method (MD5, SHA512, MD5_NONCE) for authenticating with the router. It iterates through available methods and attempts a login with each, returning the first one that succeeds. This is particularly useful during initial setup when the authentication method is unknown. Returns `None` if no method works. ```APIDOC ## `get_encryption_method()` — auto-detect authentication method Iterates over all `EncryptionMethod` values (MD5, SHA512, MD5_NONCE), attempts a login with each, and returns the first one that succeeds. Useful during initial setup when the correct method is unknown. Returns `None` if no method works. ```python import asyncio from sagemcom_api.client import SagemcomClient async def main(): # Pass no authentication_method so get_encryption_method can probe all options client = SagemcomClient("192.168.1.1", "admin", "mypassword") method = await client.get_encryption_method() if method: print(f"Use EncryptionMethod.{method.name} for this router") else: print("No compatible encryption method found — check host and credentials") await client.close() asyncio.run(main()) # Output: Use EncryptionMethod.SHA512 for this router ``` ``` -------------------------------- ### Run Speed Test and Get Results Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Triggers a speed test from the router and retrieves historical test results. The `run_speed_test` function initiates the test, and `get_speed_test_results` fetches a list of `SpeedTestResult` objects. ```APIDOC ## `run_speed_test()` and `get_speed_test_results()` — on-router speed test `run_speed_test()` triggers a speed test from the router itself (optionally blocking other traffic during the test). `get_speed_test_results()` retrieves the history of past tests as a list of `SpeedTestResult` dataclass instances containing timestamp, server address, latency, upload Mbps, and download Mbps. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() # Kick off a speed test (returns immediately; the router runs it in the background) await client.run_speed_test(block_traffic=False) # Wait a moment, then retrieve results await asyncio.sleep(30) results = await client.get_speed_test_results() for r in results: print(r) # e.g. timestamp: 2024-03-15 10:22:01, latency: 12ms, upload: 48.3, download: 195.7 asyncio.run(main()) ``` ``` -------------------------------- ### Initialize SagemcomClient with Async Context Manager Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Use SagemcomClient as an async context manager for automatic session closing. Pass custom aiohttp session for advanced configuration. ```python import asyncio from aiohttp import ClientSession, ClientTimeout from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod # Basic usage with async context manager (session closed automatically) async def main(): async with SagemcomClient( host="192.168.1.1", username="admin", password="mypassword", authentication_method=EncryptionMethod.SHA512, verify_ssl=False, # disable cert verification for self-signed certs ) as client: await client.login() info = await client.get_device_info() print(info.model_name) # e.g. "F@st 5689E" # Pass a custom aiohttp session to control timeouts, proxies, etc. custom_session = ClientSession(timeout=ClientTimeout(total=30)) client2 = SagemcomClient( host="192.168.1.1", username="guest", password="", authentication_method=EncryptionMethod.MD5, session=custom_session, ) await client2.login() await client2.close() # must close manually when not using context manager asyncio.run(main()) ``` -------------------------------- ### Login to Sagemcom Router with Exception Handling Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Authenticate with the router and handle potential connection, timeout, or authentication errors. Ensure the correct EncryptionMethod is used. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( LoginTimeoutException, LoginConnectionException, AuthenticationException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "secret", EncryptionMethod.MD5) as client: try: await client.login() print("Logged in successfully") except LoginConnectionException: print("Cannot reach host — check IP address") except LoginTimeoutException: print("Timed out — try a different EncryptionMethod") except AuthenticationException: print("Wrong username or password") asyncio.run(main()) ``` -------------------------------- ### login() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Authenticates with the router and establishes a session. This method must be called before retrieving any data. ```APIDOC ## login() ### Description Authenticates with the router by sending a `logIn` JSON-RPC action. It handles nonce exchange, stores the session ID, and returns `True` upon successful authentication. This method is a prerequisite for all data-retrieval operations. ### Method `await client.login()` ### Parameters None ### Returns - `True` if login is successful. ### Exceptions - `LoginTimeoutException`: Raised if the `authentication_method` is incorrect or the host is unreachable within the timeout period. - `LoginConnectionException`: Raised if the host cannot be reached (e.g., incorrect IP address). - `AuthenticationException`: Raised if the provided username or password is incorrect. ### Example ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( LoginTimeoutException, LoginConnectionException, AuthenticationException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "secret", EncryptionMethod.MD5) as client: try: await client.login() print("Logged in successfully") except LoginConnectionException: print("Cannot reach host — check IP address") except LoginTimeoutException: print("Timed out — try a different EncryptionMethod") except AuthenticationException: print("Wrong username or password") asyncio.run(main()) ``` ``` -------------------------------- ### Download system log file Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Fetches the vendor log file URI via JSON-RPC and then retrieves the raw log text over HTTP. Returns the log content as a plain string. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() logs = await client.get_logs() # Print the last 20 lines of the system log for line in logs.splitlines()[-20:]: print(line) asyncio.run(main()) ``` -------------------------------- ### Run Tests with Coverage Report Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Execute tests and generate a coverage report to assess code coverage. Use `--cov=sagemcom_api` to specify the package to measure. ```bash uv run pytest --cov=sagemcom_api ``` -------------------------------- ### SagemcomClient Constructor and Context Manager Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt The SagemcomClient is the main class for interacting with the router. It can be used as an async context manager for automatic session closing or manually. ```APIDOC ## SagemcomClient ### Description The `SagemcomClient` class is the central point of interaction with the Sagemcom router API. It manages the HTTP session, authentication, and API calls. It supports asynchronous operations and can be used as an async context manager. ### Usage **As an Async Context Manager (Recommended):** This ensures the HTTP session is automatically closed upon exiting the `async with` block. ```python import asyncio from aiohttp import ClientSession, ClientTimeout from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient( host="192.168.1.1", username="admin", password="mypassword", authentication_method=EncryptionMethod.SHA512, verify_ssl=False, # disable cert verification for self-signed certs ) as client: await client.login() info = await client.get_device_info() print(info.model_name) # e.g. "F@st 5689E" asyncio.run(main()) ``` **Manual Session Management:** If not using the context manager, you must manually close the client session. ```python import asyncio from aiohttp import ClientSession, ClientTimeout from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): custom_session = ClientSession(timeout=ClientTimeout(total=30)) client2 = SagemcomClient( host="192.168.1.1", username="guest", password="", authentication_method=EncryptionMethod.MD5, session=custom_session, ) await client2.login() # ... perform operations ... await client2.close() # must close manually when not using context manager asyncio.run(main()) ``` ### Parameters - **host** (str) - Required - The IP address or hostname of the Sagemcom router. - **username** (str) - Required - The username for router authentication. - **password** (str) - Required - The password for router authentication. - **authentication_method** (EncryptionMethod) - Required - The encryption method to use (e.g., `EncryptionMethod.MD5`, `EncryptionMethod.SHA512`). - **verify_ssl** (bool) - Optional - Whether to verify SSL certificates. Defaults to `True`. - **session** (aiohttp.ClientSession) - Optional - A custom `aiohttp.ClientSession` instance to use. If not provided, a new session will be created. ``` -------------------------------- ### Using Custom aiohttp ClientSession with Sagemcom API Source: https://github.com/imicknl/python-sagemcom-api/blob/main/README.md This snippet illustrates how to provide a custom `aiohttp.ClientSession` to the `SagemcomClient`. This is useful for configuring advanced session settings such as custom timeouts, allowing for more control over network requests. ```python from aiohttp import ClientSession, ClientTimeout session = ClientSession(timeout=ClientTimeout(100)) client = SagemcomClient(session=session) ``` -------------------------------- ### Exception Handling Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Demonstrates how to catch various exceptions that may occur during API operations, such as login failures, authentication errors, and invalid parameters. ```APIDOC ## Exception hierarchy All exceptions inherit from `BaseSagemcomException`. Catching specific subclasses allows fine-grained error handling. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( BaseSagemcomException, LoginTimeoutException, LoginConnectionException, AuthenticationException, InvalidSessionException, NonWritableParameterException, UnknownPathException, AccessRestrictionException, MaximumSessionCountException, LoginRetryErrorException, UnsupportedHostException, BadRequestException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: try: await client.login() await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") except LoginTimeoutException: print("Wrong encryption method or host unreachable") except LoginConnectionException: print("Cannot connect — check host IP") except AuthenticationException: print("Bad username/password") except MaximumSessionCountException: print("Too many active sessions — reboot router or wait") except NonWritableParameterException: print("Parameter is read-only") except UnknownPathException: print("XPath not found on this firmware") except AccessRestrictionException: print("Insufficient privileges for this parameter") except UnsupportedHostException: print("API endpoint not available on this host") except BaseSagemcomException as e: print(f"Sagemcom error: {e}") asyncio.run(main()) ``` ``` -------------------------------- ### Test Successful Login Flow Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Tests the successful login process by mocking the session and response. Demonstrates the session_id/nonce exchange. ```python @pytest.mark.asyncio async def test_login_success(mock_session_factory, login_success_response): """Test successful login flow.""" # Demonstrates mocking login with session_id/nonce exchange ``` -------------------------------- ### get_device_info() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Retrieves detailed information about the router, including hardware and firmware specifics. It returns a `DeviceInfo` dataclass containing the MAC address, serial number, model name, software and hardware versions, uptime, and more. If the combined `Device/DeviceInfo` path is not supported, it falls back to querying individual XPath fields. ```APIDOC ## `get_device_info()` — retrieve router hardware and firmware details Returns a `DeviceInfo` dataclass populated with MAC address, serial number, model name, software/hardware versions, uptime, and more. Falls back to querying individual XPath fields if the combined `Device/DeviceInfo` path is unsupported. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() info = await client.get_device_info() print(f"ID (MAC): {info.id}") # e.g. "AA:BB:CC:DD:EE:FF" print(f"Manufacturer: {info.manufacturer}") # e.g. "Sagemcom" print(f"Model name: {info.model_name}") # e.g. "F@st 5689E" print(f"Software version: {info.software_version}") print(f"Serial number: {info.serial_number}") print(f"Uptime (s): {info.up_time}") asyncio.run(main()) ``` ``` -------------------------------- ### reboot() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Initiates a reboot sequence for the router. After this command is sent, the router will restart, and the connection will be temporarily lost. The router is typically unreachable for 60-120 seconds following a reboot. ```APIDOC ## `reboot()` — reboot the router Sends a `reboot` action to the router. The router will immediately restart; the connection will drop shortly after the call returns. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() result = await client.reboot() print("Reboot command sent", result) # Router will be unreachable for ~60–120 seconds asyncio.run(main()) ``` ``` -------------------------------- ### Handle Sagemcom API Exceptions Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Demonstrates how to catch various exceptions that can occur during API interactions, from connection issues to authentication and parameter errors. Catching `BaseSagemcomException` provides a fallback for unhandled errors. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( BaseSagemcomException, LoginTimeoutException, LoginConnectionException, AuthenticationException, InvalidSessionException, NonWritableParameterException, UnknownPathException, AccessRestrictionException, MaximumSessionCountException, LoginRetryErrorException, UnsupportedHostException, BadRequestException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: try: await client.login() await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") except LoginTimeoutException: print("Wrong encryption method or host unreachable") except LoginConnectionException: print("Cannot connect — check host IP") except AuthenticationException: print("Bad username/password") except MaximumSessionCountException: print("Too many active sessions — reboot router or wait") except NonWritableParameterException: print("Parameter is read-only") except UnknownPathException: print("XPath not found on this firmware") except AccessRestrictionException: print("Insufficient privileges for this parameter") except UnsupportedHostException: print("API endpoint not available on this host") except BaseSagemcomException as e: print(f"Sagemcom error: {e}") asyncio.run(main()) ``` -------------------------------- ### Retrieve Port Mapping Rules Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Fetches all configured NAT/port forwarding rules. Returns a list of `PortMapping` objects detailing the status (enabled/disabled), protocol, external and internal ports, internal client IP, and description. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() mappings = await client.get_port_mappings() for pm in mappings: status = "enabled" if pm.enable else "disabled" print( f"[{status}] {pm.protocol} " f":{pm.external_port} → {pm.internal_client}:{pm.internal_port} " f"({pm.description})" ) # e.g. [enabled] TCP :8080 → 192.168.1.100:80 (Web Server) asyncio.run(main()) ``` -------------------------------- ### Write multiple router parameters by XPaths Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Batches multiple `setValue` actions into a single API call. Accepts a dictionary mapping XPath strings to their desired values. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() await client.set_values_by_xpaths({ "Device/UserInterface/AdvancedMode": "true", "Device/UserInterface/CurrentLanguage": "en", }) print("Both parameters updated in one round-trip") asyncio.run(main()) ``` -------------------------------- ### get_logs() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Fetches the vendor log file URI via JSON-RPC and then retrieves the raw log text over HTTP. Returns the log content as a plain string. ```APIDOC ## `get_logs()` — download system log file Fetches the vendor log file URI via JSON-RPC and then retrieves the raw log text over HTTP. Returns the log content as a plain string. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() logs = await client.get_logs() # Print the last 20 lines of the system log for line in logs.splitlines()[-20:]: print(line) asyncio.run(main()) ``` ``` -------------------------------- ### Retrieve Device Information Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Fetches router hardware and firmware details, including MAC address, serial number, model, and software/hardware versions. It falls back to individual XPath queries if the combined path is unsupported. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() info = await client.get_device_info() print(f"ID (MAC): {info.id}") # e.g. "AA:BB:CC:DD:EE:FF" print(f"Manufacturer: {info.manufacturer}") # e.g. "Sagemcom" print(f"Model name: {info.model_name}") # e.g. "F@st 5689E" print(f"Software version: {info.software_version}") print(f"Serial number: {info.serial_number}") print(f"Uptime (s): {info.up_time}") asyncio.run(main()) ``` -------------------------------- ### Run All Tests with Pytest Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Execute all tests in the suite using the `uv run pytest` command. This is the primary command for running the full test suite. ```bash uv run pytest ``` -------------------------------- ### Run Tests with HTML Coverage Report Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Generate an HTML report for code coverage analysis. This provides a browsable report of test coverage. ```bash uv run pytest --cov=sagemcom_api --cov-report=html ``` -------------------------------- ### get_hosts() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Lists all devices connected to the router, including both active and inactive ones. It returns a list of `Device` dataclass instances. You can filter this list to show only currently connected devices by passing `only_active=True`. ```APIDOC ## `get_hosts()` — list devices connected to the router Returns a list of `Device` dataclass instances representing every host the router knows about (both active and inactive). Pass `only_active=True` to filter to currently connected devices only. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() # All known hosts all_hosts = await client.get_hosts() print(f"Total known devices: {len(all_hosts)}") # Only currently connected devices active_hosts = await client.get_hosts(only_active=True) for device in active_hosts: print(f"{device.id} | {device.name} | {device.ip_address} | {device.interface_type}") # e.g. "AA:BB:CC:11:22:33 | my-laptop | 192.168.1.42 | WiFi" asyncio.run(main()) ``` ``` -------------------------------- ### Password Salt Workaround Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Provides a solution for specific firmware versions that require a salt appended to the password for authentication. The salt can be retrieved from the router's browser login page. ```APIDOC ## Password salt workaround (debugging `XMO_AUTHENTICATION_ERR`) Some firmware versions require a salt appended to the password. Retrieve it from the router's browser login page via `jQuery.gui.opt.GUI_PASSWORD_SALT` and append it with a colon separator. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): # If the firmware uses "Salt123" as the password salt: async with SagemcomClient( "192.168.1.1", "admin", "myPassword:Salt123", EncryptionMethod.SHA512 ) as client: await client.login() info = await client.get_device_info() print(info.model_name) asyncio.run(main()) ``` ``` -------------------------------- ### Test Sequential API Responses Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Demonstrates how to mock multiple sequential responses for API operations that require a sequence of requests, such as login followed by another operation. The `mock_session_factory` is used with a list of responses. ```python # Two sequential responses mock_session = mock_session_factory([login_success_response, xpath_value_response]) await client.login() # Consumes login_success_response (1st call) await client.get_value_by_xpath() # Consumes xpath_value_response (2nd call) await client.logout() # Would raise StopIteration (no 3rd response) ``` -------------------------------- ### Test Authentication Error Handling Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Verifies that an `AuthenticationException` is raised when the API returns an `XMO_AUTHENTICATION_ERR` status. This test mocks the error response. ```python @pytest.mark.asyncio async def test_authentication_error(mock_session_factory, login_auth_error_response): """Test AuthenticationException is raised on XMO_AUTHENTICATION_ERR.""" # Demonstrates error response mocking ``` -------------------------------- ### Mock API Response Structure Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Illustrates the JSON structure of a typical Sagemcom API response, including error codes and action callbacks. This format is used for creating mock response fixtures. ```json { "reply": { "error": {"description": "XMO_REQUEST_NO_ERR"}, "actions": [{ "callbacks": [{ "parameters": {"id": 12345, "nonce": "abcdef123456"} }] }] } } ``` -------------------------------- ### get_port_mappings() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Retrieves all configured NAT/port forwarding rules on the router. It returns a list of `PortMapping` dataclass instances, each detailing the external port, internal IP address, protocol, and description of the rule. ```APIDOC ## `get_port_mappings()` — retrieve NAT/port forwarding rules Returns a list of `PortMapping` dataclass instances describing every configured port forwarding rule (external port, internal IP, protocol, etc.). ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() mappings = await client.get_port_mappings() for pm in mappings: status = "enabled" if pm.enable else "disabled" print( f"[{status}] {pm.protocol} " f":{pm.external_port} → {pm.internal_client}:{pm.internal_port} " f"({pm.description})" ) # e.g. [enabled] TCP :8080 → 192.168.1.100:80 (Web Server) asyncio.run(main()) ``` ``` -------------------------------- ### Run Specific Test Case Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Execute a single, specific test function within a file. Ideal for debugging a particular test case. ```bash uv run pytest tests/unit/test_client_basic.py::test_login_success ``` -------------------------------- ### Login with Salted Password Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/debugging.md Use this Python code to log in to the Sagemcom device when a password salt is required. Append the salt to your original password, separated by a colon. ```python async with SagemcomClient(HOST, USERNAME, "myPassword:Salt123", ENCRYPTION_METHOD) as client: try: await client.login() except Exception as exception: # pylint: disable=broad-except print(exception) ``` -------------------------------- ### Write single router parameter by XPath Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Sets a single node in the router's data model using XPath. Catches exceptions for read-only parameters, unknown paths, or insufficient user permissions. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( NonWritableParameterException, UnknownPathException, AccessRestrictionException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() try: await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") print("Parameter updated") except NonWritableParameterException: print("This parameter is read-only on your firmware") except UnknownPathException: print("XPath does not exist on this router") except AccessRestrictionException: print("Current user cannot modify this parameter") asyncio.run(main()) ``` -------------------------------- ### Configure SagemcomClient with Specific Cipher Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/ssl-error.md Use this snippet to configure the SagemcomClient to use a specific cipher suite, such as AES256-GCM-SHA384, and disable certificate validation. This is useful when encountering SSL handshake failures due to cipher mismatches. ```python async def main() -> None: sslcontext = ssl._create_unverified_context() sslcontext.set_ciphers("AES256-GCM-SHA384") session = ClientSession( headers={"User-Agent": f"{DEFAULT_USER_AGENT}"}, timeout=ClientTimeout(DEFAULT_TIMEOUT), connector=TCPConnector( ssl_context=sslcontext ) ) async with SagemcomClient(HOST, USERNAME, PASSWORD, ENCRYPTION_METHOD, session=session) as client: ``` -------------------------------- ### Password Salt Workaround for Authentication Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Applies a workaround for firmware versions requiring a salt appended to the password. Retrieve the salt from the router's login page and append it to the password with a colon separator. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): # If the firmware uses "Salt123" as the password salt: async with SagemcomClient( "192.168.1.1", "admin", "myPassword:Salt123", EncryptionMethod.SHA512 ) as client: await client.login() info = await client.get_device_info() print(info.model_name) asyncio.run(main()) ``` -------------------------------- ### logout() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Closes the current session with the router. Recommended when not using the async context manager. ```APIDOC ## logout() ### Description Sends a `logOut` JSON-RPC action to the router to terminate the current session and resets the internal session state of the client. This is good practice, especially when the `SagemcomClient` is not used as an async context manager. ### Method `await client.logout()` ### Parameters None ### Returns None ### Example ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): client = SagemcomClient("192.168.1.1", "guest", "", EncryptionMethod.SHA512) await client.login() # ... perform operations ... await client.logout() await client.close() # Ensure the underlying session is closed if not using context manager asyncio.run(main()) ``` ``` -------------------------------- ### Read multiple router parameters by XPaths Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Batches multiple XPath queries into a single API call for efficiency. Accepts a dictionary mapping result keys to XPath strings and returns a dictionary with the same keys mapped to their values. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() values = await client.get_values_by_xpaths({ "advanced_mode": "Device/UserInterface/AdvancedMode", "dns_servers": "Device/DNS/Client/Servers", "wan_ip": "Device/IP/Interfaces/Interface[@uid='1']/IPAddress", }) print(values["wan_ip"]) print(values["dns_servers"]) asyncio.run(main()) ``` -------------------------------- ### Handle Exceptions in Sagemcom API Calls Source: https://github.com/imicknl/python-sagemcom-api/blob/main/README.md This snippet shows how to handle specific exceptions like `NonWritableParameterException` and `UnknownPathException` when interacting with the Sagemcom router via XPath. It's recommended to catch specific errors for graceful error management. ```python from sagemcom_api.exceptions import * try: await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") except NonWritableParameterException as exception: print("You don't have rights to write to this parameter.") except UnknownPathException as exception: print("The xpath does not exist.") ``` -------------------------------- ### Run Coverage Report Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Execute pytest with coverage enabled to generate a report showing missing coverage. Use `--cov-report=term-missing` to display lines lacking coverage. ```bash uv run pytest --cov=sagemcom_api --cov-report=term-missing ``` -------------------------------- ### Run Specific Test File Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Execute tests contained within a single specified file. Useful for isolating issues within a particular test file. ```bash uv run pytest tests/unit/test_client_basic.py ``` -------------------------------- ### Read router parameter by XPath Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Queries a single node in the router's data model using XPath. Returns a dictionary of the value(s) at that path. Use this for parameters not covered by helper methods. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import UnknownPathException async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() # Read a simple boolean flag result = await client.get_value_by_xpath("Device/UserInterface/AdvancedMode") print(result) # e.g. {'advanced_mode': False} # Read a richer subtree try: summary = await client.get_value_by_xpath("Device/DeviceSummary") print(summary) except UnknownPathException: print("DeviceSummary path not supported on this firmware") asyncio.run(main()) ``` -------------------------------- ### Check for GUI Password Salt Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/debugging.md Evaluate this JavaScript expression in your browser's debug console to find the password salt used by your device. This is necessary if you are encountering authentication errors. ```javascript jQuery.gui.opt.GUI_PASSWORD_SALT ``` -------------------------------- ### Reboot Router Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Sends a reboot command to the router. The connection will be lost immediately after the command is sent and the router will restart, becoming unreachable for approximately 60-120 seconds. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() result = await client.reboot() print("Reboot command sent", result) # Router will be unreachable for ~60–120 seconds asyncio.run(main()) ``` -------------------------------- ### set_values_by_xpaths() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Batches multiple `setValue` actions into a single API call. Accepts a `dict` mapping XPath strings to their desired values. ```APIDOC ## `set_values_by_xpaths()` — write multiple router parameters in one request Batches multiple `setValue` actions into a single API call. Accepts a `dict` mapping XPath strings to their desired values. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() await client.set_values_by_xpaths({ "Device/UserInterface/AdvancedMode": "true", "Device/UserInterface/CurrentLanguage": "en", }) print("Both parameters updated in one round-trip") asyncio.run(main()) ``` ``` -------------------------------- ### set_value_by_xpath() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Sets one node in the router's data model. Raises `NonWritableParameterException` if the parameter is read-only, `UnknownPathException` if the path does not exist, and `AccessRestrictionException` if the current user lacks permission. ```APIDOC ## `set_value_by_xpath()` — write a single router parameter via XPath Sets one node in the router's data model. Raises `NonWritableParameterException` if the parameter is read-only, `UnknownPathException` if the path does not exist, and `AccessRestrictionException` if the current user lacks permission. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import ( NonWritableParameterException, UnknownPathException, AccessRestrictionException, ) async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() try: await client.set_value_by_xpath("Device/UserInterface/AdvancedMode", "true") print("Parameter updated") except NonWritableParameterException: print("This parameter is read-only on your firmware") except UnknownPathException: print("XPath does not exist on this router") except AccessRestrictionException: print("Current user cannot modify this parameter") asyncio.run(main()) ``` ``` -------------------------------- ### get_values_by_xpaths() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Batches multiple XPath queries into a single API call. Accepts a `dict` mapping result keys to XPath strings and returns a `dict` with the same keys mapped to their values. More efficient than calling `get_value_by_xpath()` repeatedly. ```APIDOC ## `get_values_by_xpaths()` — read multiple router parameters in one request Batches multiple XPath queries into a single API call. Accepts a `dict` mapping result keys to XPath strings and returns a `dict` with the same keys mapped to their values. More efficient than calling `get_value_by_xpath()` repeatedly. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() values = await client.get_values_by_xpaths({ "advanced_mode": "Device/UserInterface/AdvancedMode", "dns_servers": "Device/DNS/Client/Servers", "wan_ip": "Device/IP/Interfaces/Interface[@uid='1']/IPAddress", }) print(values["wan_ip"]) # e.g. "203.0.113.45" print(values["dns_servers"]) # e.g. [{'address': '8.8.8.8'}, ...] asyncio.run(main()) ``` ``` -------------------------------- ### List Connected Devices Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Retrieves a list of all known devices connected to the router, including inactive ones. Use `only_active=True` to filter for currently connected devices only. Displays device ID, name, IP address, and interface type. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.MD5) as client: await client.login() # All known hosts all_hosts = await client.get_hosts() print(f"Total known devices: {len(all_hosts)}") # Only currently connected devices active_hosts = await client.get_hosts(only_active=True) for device in active_hosts: print(f"{device.id} | {device.name} | {device.ip_address} | {device.interface_type}") # e.g. "AA:BB:CC:11:22:33 | my-laptop | 192.168.1.42 | WiFi" asyncio.run(main()) ``` -------------------------------- ### Logout from Sagemcom Router Session Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Close the router session and reset internal state. Recommended when not using the async context manager. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod async def main(): client = SagemcomClient("192.168.1.1", "guest", "", EncryptionMethod.SHA512) await client.login() # ... do work ... await client.logout() await client.close() asyncio.run(main()) ``` -------------------------------- ### Run Only Unit Tests with Pytest Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Filter test execution to include only unit tests by specifying the `tests/unit/` directory. Useful for focused testing. ```bash uv run pytest tests/unit/ ``` -------------------------------- ### get_value_by_xpath() Source: https://context7.com/imicknl/python-sagemcom-api/llms.txt Queries a single node in the router's data model using XPath notation. Returns a dict (converted to snake_case) containing the value(s) at that path. This is the low-level escape hatch for any parameter not covered by a helper method. ```APIDOC ## `get_value_by_xpath()` — read any router parameter via XPath Queries a single node in the router's data model using XPath notation. Returns a dict (converted to snake_case) containing the value(s) at that path. This is the low-level escape hatch for any parameter not covered by a helper method. ```python import asyncio from sagemcom_api.client import SagemcomClient from sagemcom_api.enums import EncryptionMethod from sagemcom_api.exceptions import UnknownPathException async def main(): async with SagemcomClient("192.168.1.1", "admin", "pass", EncryptionMethod.SHA512) as client: await client.login() # Read a simple boolean flag result = await client.get_value_by_xpath("Device/UserInterface/AdvancedMode") print(result) # e.g. {'advanced_mode': False} # Read a richer subtree try: summary = await client.get_value_by_xpath("Device/DeviceSummary") print(summary) except UnknownPathException: print("DeviceSummary path not supported on this firmware") asyncio.run(main()) ``` ``` -------------------------------- ### Test XPath URL Encoding Source: https://github.com/imicknl/python-sagemcom-api/blob/main/docs/testing.md Validates that XPath values are correctly URL-encoded, ensuring that characters like `/`, `=`, `[` and `]` are preserved. This test focuses on the encoding mechanism. ```python @pytest.mark.asyncio async def test_xpath_url_encoding(mock_session_factory): """Test XPath values are URL-encoded with /=[]' preserved.""" # Demonstrates XPath encoding validation ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.