Observed since 20 Oct, 21:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Asynchronous implementation of the Frontier Silicon API
Asynchronous Python implementation of the Frontier Silicon API
Runtime dependency:
Development workflow (uv + ruff):
uv sync --group dev
uv run ruff check .
uv run pytest -q
The repository includes integration tests that can record and replay real responses from the development radio.
tests/test_device_recordings.py (read calls) and
tests/test_device_recordings_write.py (write calls with state restore).tests/cassettes/.pytest runs them with no live device access).AFSAPI_DEVICE_IP and AFSAPI_DEVICE_PIN.Set device IP + PIN and record fresh cassettes:
AFSAPI_DEVICE_IP="192.168.1.183" AFSAPI_DEVICE_PIN="1234" uv run pytest tests/test_device_recordings.py tests/test_device_recordings_write.py --run-device-tests --record-mode=once -q
Re-record all cassettes:
AFSAPI_DEVICE_IP="192.168.1.183" AFSAPI_DEVICE_PIN="1234" uv run pytest tests/test_device_recordings.py tests/test_device_recordings_write.py --run-device-tests --record-mode=all -q
Run default tests without touching the device:
uv run pytest -q
nav_list() and get(Nodes.nav_list) collect the complete directory before
returning items. Some radios need additional time after enabling navigation or
changing folders: list reads can raise FSNodeBlockedError or return an
FS_OK loading placeholder with item type 255 (sometimes without a name).
These two conditions trigger up to 8 complete read attempts, separated by
1 second: at most 7 seconds of added retry sleeps, not an overall
wall-clock timeout. HTTP request timeouts and time spent reading all pages are
additional. A successful first read incurs no extra delay.
Each retry starts reading from the first page and discards the incomplete
attempt; partial results are never yielded or duplicated. If the last read is
still blocked, its FSNodeBlockedError is propagated. A persistent loading
placeholder raises FSNodeBlockedError with a loading-specific message.
Other errors and cancellation propagate without readiness retries. Navigation
SET commands, other endpoints, and the low-level handle_list() iterator keep
their existing behavior; no navigation state changes are replayed by this retry
policy. A genuinely empty list remains an empty list.
This handles delayed readiness, not changes made by other clients to the radio's global navigation state, nor pagination/cadence limits on very large station directories.
import asyncio
from afsapi import AFSAPI
URL = 'http://192.168.1.XYZ:80/device'
PIN = 1234
TIMEOUT = 1 # in seconds
async def test():
afsapi = await AFSAPI.create(URL, PIN, TIMEOUT)
print(f'Set power succeeded? - {await afsapi.set_power(True)}' )
print(f'Power on: {await afsapi.get_power()}')
print(f'Friendly name: {await afsapi.get_friendly_name()}')
for mode in await afsapi.get_modes():
print(f'Available Mode: {mode}')
print(f'Current Mode: {await afsapi.get_mode()}')
for equaliser in await afsapi.get_equalisers():
print(f'Equaliser: {equaliser}')
print(f'EQ Preset: {await afsapi.get_eq_preset()}' )
for preset in await afsapi.get_presets():
print(f"Preset: {preset}")
print(f'Set power succeeded? - {await afsapi.set_power(False)}')
print(f'Set sleep succeeded? - {await afsapi.set_sleep(10)}')
print(f'Sleep: {await afsapi.get_sleep()}')
print(f'Get power {await afsapi.get_power()}' )
loop = asyncio.new_event_loop()
loop.run_until_complete(test())
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.0.3 | 16 Oct 2026 | 2 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:cb7005b0897d1fbf89fe89ccf59da3fd89cae461894f35e5e7d9fd90aea605e8