Skip to content

Commit

Permalink
feat: add client documentation (#36)
Browse files Browse the repository at this point in the history
* feat: add client documentation
* fix: Db model (Draws a RGB888 bitmap array)
  • Loading branch information
M0NsTeRRR authored Feb 17, 2024
1 parent ffb1e40 commit 3567d0c
Show file tree
Hide file tree
Showing 31 changed files with 1,682 additions and 72 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,12 @@ jobs:
export PATH="$PATH:$HOME/.local/bin"
source `poetry env info --path`/bin/activate
poetry version $(git describe --tags --abbrev=0)
poetry publish --build -u __token__ -p ${{ secrets.PYPI_API_TOKEN }}
poetry publish --build -u __token__ -p ${{ secrets.PYPI_API_TOKEN }}
- name: Deploy documentation
run: |
export PATH="$PATH:$HOME/.local/bin"
source `poetry env info --path`/bin/activate
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
poetry run mike deploy --push --update-aliases $(git describe --tags --abbrev=0) latest
poetry run mike set-default --push latest
46 changes: 2 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ Python async HTTP client for [awtrix-light](https://github.com/Blueforcer/awtrix
# Warning
This client has been tested with awtrix-light v0.90 use with caution as official dev documentation is not fully documented and can cause crash

# Install
```
pip install awtrix-light-client
```
# Documentation
[https://M0NsTeRRR.github.io/awtrix-light-client](https://M0NsTeRRR.github.io/awtrix-light-client)

# Dev
Install [Poetry](https://python-poetry.org/docs/master/#installing-with-the-official-installer)
Expand All @@ -22,46 +20,6 @@ poetry install
poetry shell
```

# Usage
Official project documentation : https://blueforcer.github.io/awtrix-light/#/api

Available environment variables
```
AWTRIX_HTTP_CLIENT_AWTRIX="<AWTRIX CONFIG>"
```

`<AWTRIX CONFIG>` is in JSON and looks like this :
```json
{
"base_url": "http://192.168.0.1",
"username": "admin",
"password": "password",
"verify_ssl": false
}
```
`verify_ssl` used to verify https config (if accessing behind an HTTPS reverse proxy), can be `true`, `false`, or can point to a local ca bundle PEM encoded to validate local CA

Environment variables can also be placed in a `.env` in the working directory.

Example script
```py
import asyncio

from awtrix_light_client.http_client import get_awtrix_http_client, AwtrixLightHttpClientError


async def main():
try:
async with get_awtrix_http_client() as client:
stats = await client.get_stats()
print(stats)
except AwtrixLightHttpClientError as e:
print(f"HTTP code: {e.status_code}, error content: {e.content}")


asyncio.run(main())
```

### Run unit test
```
poetry run pytest --cov
Expand Down
43 changes: 35 additions & 8 deletions awtrix_light_client/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@


class AwtrixLightHttpClientError(BaseException):
"""Class of API exception
:param status_code: HTTP status code of the response
:param content: HTTP content of the response
"""

def __init__(self, status_code: int, content: str, *args: object) -> None:
super().__init__(*args)
self.status_code = status_code
Expand All @@ -25,6 +31,9 @@ def __init__(self, status_code: int, content: str, *args: object) -> None:

class AwtrixLightHttpClient:
def __init__(self, client: AsyncClient) -> None:
"""
:param client: `AsyncClient`
"""
self._client = client

async def _make_request(
Expand All @@ -34,6 +43,7 @@ async def _make_request(
params: Dict[Any, Any] = None,
data: Dict[Any, Any] = None,
):
"""Boilerplate to make request to the APU. Handling error is done for you here."""
r = await self._client.request(method, url, params=params, json=data)

if not r.is_success:
Expand All @@ -45,6 +55,7 @@ async def _make_request(
async def get_stats(self) -> Stats:
"""
General device stats (e.g., battery, RAM)
:return: Return a `Stats` object
"""
response = (await self._make_request("GET", "stats")).json()

Expand All @@ -53,6 +64,7 @@ async def get_stats(self) -> Stats:
async def get_effects(self) -> List[EffectType]:
"""
List of all effects
:return: Return a list of `EffectType` object
"""
response = (await self._make_request("GET", "effects")).json()

Expand All @@ -61,6 +73,7 @@ async def get_effects(self) -> List[EffectType]:
async def get_transitions(self) -> List[TransitionType]:
"""
List of all transition effects
:return: Return a list of `TransitionType` object
"""
response = (await self._make_request("GET", "transitions")).json()

Expand All @@ -69,6 +82,7 @@ async def get_transitions(self) -> List[TransitionType]:
async def get_loops(self) -> Loop:
"""
List of all apps in the loop
:return: Return a `Loop` object
"""
response = (await self._make_request("GET", "loop")).json()

Expand All @@ -79,6 +93,7 @@ async def get_loops(self) -> Loop:
async def get_screen(self) -> Screen:
"""
Retrieve the current matrix screen as an array of 24 bit colors
:return: Return a `Screen` object
"""
response = (await self._make_request("GET", "screen")).json()

Expand All @@ -87,31 +102,35 @@ async def get_screen(self) -> Screen:
async def set_power(self, power: bool) -> None:
"""
Toggle the matrix on or off
:param power: Toggle the matrix
"""
await self._make_request("POST", "power", data={"power": power})

async def set_sleep(self, seconds: int) -> None:
"""
Send the board in deep sleep mode (turns off the matrix as well), good for saving battery life
:param seconds: Duration of sleep mode
"""
await self._make_request("POST", "sleep", data={"sleep": seconds})

async def set_sound(self, sound: str) -> None:
"""
Play a RTTTL sound from the MELODIES folder
:param sound: Sound to play
"""
await self._make_request("POST", "sound", data={"sound": sound})

async def set_rtttl(self, rtttl: str) -> None:
"""
Play a RTTTL sound from a given RTTTL string
:param sound: Sound to play in RTTTL format
"""
await self._make_request("POST", "rtttl", data={"rtttl": rtttl})

async def set_moodlight(self, moodlight: Moodlight) -> None:
"""
Set the entire matrix to a custom color or temperature
To disable moodlight pass `Moodlight()`
:param moodlight: Custom color or temperature to set. To disable moodlight pass an empty object `Moodlight()`
"""
await self._make_request(
"POST", "moodlight", data=moodlight.model_dump(exclude_none=True)
Expand All @@ -126,12 +145,10 @@ async def set_indicator(
) -> None:
"""
Colored indicators serve as small notification signs displayed on specific areas of the screen:
Upper right corner: Indicator 1
Right side: Indicator 2
Lower right corner: Indicator 3
To hide the indicators pass black as Color
Blink is in milliseconds
Fade is in milliseconds
:param indicator: Indicator (Upper right corner = 1, Right side = 2, Lower right corner = 3)
:param color: Color to display. To hide the indicators pass black as Color
:param blink: Blink timer in milliseconds
:param fade: Fade timer in milliseconds
"""
if blink and fade:
raise ValueError("fade and blink can't be set together")
Expand Down Expand Up @@ -160,6 +177,8 @@ async def set_custom_application(
When erasing apps, AWTRIX doesn't match the exact app name. Instead, it identifies apps that begin with the specified name.
To expunge all associated apps, send application=None. For example for name=test. This action will remove test0, test1, and so on.
To eradicate a single app, direct the command to, for instance, test1
:param name: Name of the application to manage
:param custom_application: An application, a list of application to setup or None
"""
if isinstance(custom_application, CustomApplication):
data = custom_application.model_dump(exclude_none=True)
Expand All @@ -171,6 +190,7 @@ async def set_custom_application(
async def notify(self, notification: Notification) -> None:
"""
One-Time Notification
:param notification: Notification to display
"""
await self._make_request(
"POST", "notify", data=notification.model_dump(exclude_none=True)
Expand All @@ -197,18 +217,21 @@ async def previous_app(self) -> None:
async def switch_app(self, name: str) -> None:
"""
Directly transition to a desired app using its name
:param name: Application to switch to
"""
await self._make_request("POST", "switch", data={"name": name})

async def get_settings(self) -> Settings:
"""
You can initiate the firmware update either through the update button in HA or using the following
:return: Return a `Settings` object
"""
return Settings(**(await self._make_request("GET", "settings")).json())

async def set_settings(self, s: Settings) -> None:
"""
You can initiate the firmware update either through the update button in HA or using the following
Adjust various settings related to the app display.
:param s: Settings to update
"""
await self._make_request(
"POST", "settings", data=s.model_dump(exclude_none=True)
Expand Down Expand Up @@ -241,6 +264,10 @@ async def reset_settings(self) -> None:

@asynccontextmanager
async def get_awtrix_http_client() -> AsyncIterator[AwtrixLightHttpClient]:
"""Gives access to an instance of the Awtrix-light HTTP client
:return: An `asynccontextmanager` of `AwtrixLightHttpClient`
"""
settings = AwtrixLightHttpClientSettings()

auth = None
Expand Down
8 changes: 8 additions & 0 deletions awtrix_light_client/http_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@


class AwtrixHttpConfig(BaseModel):
"""Base model representing API configuration
:param base_url: Base URL of API
:param username: username when using HTTP basic auth
:param password: password when using HTTP basic auth
:param verify: SSL certificates (a.k.a CA bundle) used to verify the identity of requested hosts. Either True (default CA bundle), a path to an SSL certificate file, or False (which will disable verification).
"""

base_url: AnyHttpUrl
username: str = None
password: str = None
Expand Down
Empty file.
Loading

0 comments on commit 3567d0c

Please sign in to comment.