busylib 0.0.1__py3-none-any.whl → 0.0.1a0__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.
Potentially problematic release.
This version of busylib might be problematic. Click here for more details.
- busylib/__init__.py +82 -0
- busylib/client.py +108 -0
- busylib/types.py +9 -0
- busylib-0.0.1a0.dist-info/METADATA +162 -0
- busylib-0.0.1a0.dist-info/RECORD +8 -0
- busylib-0.0.1a0.dist-info/licenses/LICENSE +7 -0
- busylib-0.0.1.dist-info/METADATA +0 -19
- busylib-0.0.1.dist-info/RECORD +0 -5
- {busylib-0.0.1.dist-info → busylib-0.0.1a0.dist-info}/WHEEL +0 -0
- {busylib-0.0.1.dist-info → busylib-0.0.1a0.dist-info}/top_level.txt +0 -0
busylib/__init__.py
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main library for interacting with the Busy Bar API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import IO
|
|
6
|
+
|
|
7
|
+
from busylib.client import ApiClient
|
|
8
|
+
from busylib.types import ApiResponse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BusyBar:
|
|
12
|
+
"""
|
|
13
|
+
Main library class for interacting with the Busy Bar API.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, addr: str = "10.0.4.20"):
|
|
17
|
+
"""
|
|
18
|
+
Creates an instance of BUSY Bar.
|
|
19
|
+
Initializes the API client with the provided address.
|
|
20
|
+
|
|
21
|
+
:param addr: The address of the device.
|
|
22
|
+
"""
|
|
23
|
+
self._addr = addr
|
|
24
|
+
self._client = ApiClient(f"http://{self._addr}/api/")
|
|
25
|
+
|
|
26
|
+
def upload_asset(
|
|
27
|
+
self, app_id: str, file_name: str, file: bytes | IO[bytes]
|
|
28
|
+
) -> ApiResponse | None:
|
|
29
|
+
"""
|
|
30
|
+
Uploads an asset to the device.
|
|
31
|
+
|
|
32
|
+
:param app_id: Application ID for organizing assets.
|
|
33
|
+
:param file_name: Filename for the uploaded asset.
|
|
34
|
+
:param file: File data to upload (bytes or file-like object).
|
|
35
|
+
:return: Result of the upload operation.
|
|
36
|
+
"""
|
|
37
|
+
return self._client.upload_asset(app_id, file_name, file)
|
|
38
|
+
|
|
39
|
+
def delete_assets(self, app_id: str) -> ApiResponse | None:
|
|
40
|
+
"""
|
|
41
|
+
Deletes all assets for a specific application from the device.
|
|
42
|
+
|
|
43
|
+
:param app_id: Application ID whose assets should be deleted.
|
|
44
|
+
:return: Result of the delete operation.
|
|
45
|
+
"""
|
|
46
|
+
return self._client.delete_assets(app_id)
|
|
47
|
+
|
|
48
|
+
def draw_display(self, app_id: str, elements: list[dict]) -> ApiResponse | None:
|
|
49
|
+
"""
|
|
50
|
+
Draws elements on the device display.
|
|
51
|
+
|
|
52
|
+
:param app_id: Application ID for organizing display elements.
|
|
53
|
+
:param elements: Array of display elements (text or image).
|
|
54
|
+
:return: Result of the draw operation.
|
|
55
|
+
"""
|
|
56
|
+
return self._client.draw_display(app_id, elements)
|
|
57
|
+
|
|
58
|
+
def clear_display(self) -> ApiResponse | None:
|
|
59
|
+
"""
|
|
60
|
+
Clears the device display.
|
|
61
|
+
|
|
62
|
+
:return: Result of the clear operation.
|
|
63
|
+
"""
|
|
64
|
+
return self._client.clear_display()
|
|
65
|
+
|
|
66
|
+
def play_sound(self, app_id: str, path: str) -> ApiResponse | None:
|
|
67
|
+
"""
|
|
68
|
+
Plays an audio file from the assets directory.
|
|
69
|
+
|
|
70
|
+
:param app_id: Application ID for organizing assets.
|
|
71
|
+
:param path: Path to the audio file within the app's assets directory.
|
|
72
|
+
:return: Result of the play operation.
|
|
73
|
+
"""
|
|
74
|
+
return self._client.play_audio(app_id, path)
|
|
75
|
+
|
|
76
|
+
def stop_sound(self) -> ApiResponse | None:
|
|
77
|
+
"""
|
|
78
|
+
Stops any currently playing audio on the device.
|
|
79
|
+
|
|
80
|
+
:return: Result of the stop operation.
|
|
81
|
+
"""
|
|
82
|
+
return self._client.stop_audio()
|
busylib/client.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import IO
|
|
3
|
+
from busylib.types import ApiResponse
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ApiClient:
|
|
7
|
+
def __init__(self, base_url: str):
|
|
8
|
+
if not base_url.endswith("/"):
|
|
9
|
+
base_url += "/"
|
|
10
|
+
self.base_url = base_url
|
|
11
|
+
self.session = requests.Session()
|
|
12
|
+
|
|
13
|
+
def _request(
|
|
14
|
+
self,
|
|
15
|
+
method: str,
|
|
16
|
+
endpoint: str,
|
|
17
|
+
params: dict[str, object] | None = None,
|
|
18
|
+
json: object | None = None,
|
|
19
|
+
data: object | None = None,
|
|
20
|
+
headers: dict[str, str] | None = None,
|
|
21
|
+
) -> ApiResponse:
|
|
22
|
+
url = f"{self.base_url}{endpoint}"
|
|
23
|
+
try:
|
|
24
|
+
response = self.session.request(
|
|
25
|
+
method, url, params=params, json=json, data=data, headers=headers
|
|
26
|
+
)
|
|
27
|
+
response.raise_for_status()
|
|
28
|
+
if response.status_code == 204 or not response.content:
|
|
29
|
+
return None
|
|
30
|
+
# We expect a JSON response that can be mapped to our dataclass
|
|
31
|
+
data = response.json()
|
|
32
|
+
return ApiResponse(
|
|
33
|
+
success=data.get("success", True), message=data.get("message")
|
|
34
|
+
)
|
|
35
|
+
except requests.exceptions.RequestException as e:
|
|
36
|
+
# Re-raise as a custom exception for better error handling upstream
|
|
37
|
+
raise ConnectionError(f"API request failed: {e}") from e
|
|
38
|
+
|
|
39
|
+
def post(
|
|
40
|
+
self,
|
|
41
|
+
endpoint: str,
|
|
42
|
+
params: dict[str, object] = None,
|
|
43
|
+
json: object | None = None,
|
|
44
|
+
data: object | None = None,
|
|
45
|
+
headers: dict[str, str] | None = None,
|
|
46
|
+
) -> ApiResponse | None:
|
|
47
|
+
return self._request(
|
|
48
|
+
"POST", endpoint, params=params, json=json, data=data, headers=headers
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def get(
|
|
52
|
+
self, endpoint: str, params: dict[str, object] | None = None
|
|
53
|
+
) -> ApiResponse | None:
|
|
54
|
+
return self._request("GET", endpoint, params=params)
|
|
55
|
+
|
|
56
|
+
def delete(
|
|
57
|
+
self, endpoint: str, params: dict[str, object] | None = None
|
|
58
|
+
) -> ApiResponse | None:
|
|
59
|
+
return self._request("DELETE", endpoint, params=params)
|
|
60
|
+
|
|
61
|
+
def upload_asset(
|
|
62
|
+
self, app_id: str, file_name: str, file: bytes | IO[bytes]
|
|
63
|
+
) -> ApiResponse | None:
|
|
64
|
+
"""
|
|
65
|
+
Uploads an asset to the device.
|
|
66
|
+
"""
|
|
67
|
+
payload = {"app_id": app_id, "file": file_name}
|
|
68
|
+
headers = {"Content-Type": "application/octet-stream"}
|
|
69
|
+
return self.post("v0/assets/upload", params=payload, data=file, headers=headers)
|
|
70
|
+
|
|
71
|
+
def delete_assets(self, app_id: str) -> ApiResponse | None:
|
|
72
|
+
"""
|
|
73
|
+
Deletes all assets for a specific application from the device.
|
|
74
|
+
"""
|
|
75
|
+
params = {"app_id": app_id}
|
|
76
|
+
return self.delete("v0/assets/upload", params=params)
|
|
77
|
+
|
|
78
|
+
def play_audio(self, app_id: str, path: str) -> ApiResponse | None:
|
|
79
|
+
"""
|
|
80
|
+
Plays an audio file from the assets directory.
|
|
81
|
+
"""
|
|
82
|
+
params = {"app_id": app_id, "path": path}
|
|
83
|
+
return self.post("v0/audio/play", params=params)
|
|
84
|
+
|
|
85
|
+
def stop_audio(self) -> ApiResponse | None:
|
|
86
|
+
"""
|
|
87
|
+
Stops any currently playing audio on the device.
|
|
88
|
+
"""
|
|
89
|
+
return self.delete("v0/audio/play")
|
|
90
|
+
|
|
91
|
+
def draw_display(
|
|
92
|
+
self, app_id: str, elements: list[dict[str, object]]
|
|
93
|
+
) -> ApiResponse | None:
|
|
94
|
+
"""
|
|
95
|
+
Draws elements on the device display.
|
|
96
|
+
"""
|
|
97
|
+
default_values = {"timeout": 5, "x": 0, "y": 0, "display": "front"}
|
|
98
|
+
|
|
99
|
+
normalized_elements = [default_values | e for e in elements]
|
|
100
|
+
return self.post(
|
|
101
|
+
"v0/display/draw", json={"app_id": app_id, "elements": normalized_elements}
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def clear_display(self) -> ApiResponse | None:
|
|
105
|
+
"""
|
|
106
|
+
Clears the device display.
|
|
107
|
+
"""
|
|
108
|
+
return self.delete("v0/display/draw")
|
busylib/types.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: busylib
|
|
3
|
+
Version: 0.0.1a0
|
|
4
|
+
Summary: Python library for Busy Bar API
|
|
5
|
+
Author-email: Valerii Lisai <v.lisai@flipperdevices.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/busy-app/busylib
|
|
7
|
+
Project-URL: Repository, https://github.com/busy-app/busylib
|
|
8
|
+
Project-URL: Documentation, https://busylib.readthedocs.io
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: requests==2.32.4
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest==8.4.1; extra == "dev"
|
|
23
|
+
Requires-Dist: requests-mock==1.12.1; extra == "dev"
|
|
24
|
+
Requires-Dist: ruff; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# busylib
|
|
28
|
+
|
|
29
|
+
A simple and intuitive Python client for interacting with the Busy Bar API. This library allows you to programmatically control the device's display, audio, and assets.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- Easy-to-use API for all major device functions.
|
|
34
|
+
- Upload and manage assets for your applications.
|
|
35
|
+
- Control the display by drawing text and images.
|
|
36
|
+
- Play and stop audio files.
|
|
37
|
+
- Built-in validation for device IP addresses.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
You can install `busylib` directly from PyPI:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install busylib
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
First, import and initialize the `BusyBar` client with the IP address of your device.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from busylib import BusyBar
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
# Default IP is 10.0.4.20, but you can specify your own
|
|
56
|
+
bb = BusyBar("192.168.1.100")
|
|
57
|
+
except ValueError as e:
|
|
58
|
+
print(f"Error: {e}")
|
|
59
|
+
|
|
60
|
+
# Now you can use the bb object to interact with your device.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Examples
|
|
64
|
+
|
|
65
|
+
Here are some examples of how to use the library to control your Busy Bar device.
|
|
66
|
+
|
|
67
|
+
### Uploading an Asset
|
|
68
|
+
|
|
69
|
+
You can upload files (like images or sounds) to be used by your application on the device.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
# Upload a file from bytes
|
|
73
|
+
with open("path/to/your/image.png", "rb") as f:
|
|
74
|
+
file_bytes = f.read()
|
|
75
|
+
bb.upload_asset(
|
|
76
|
+
app_id="my-app",
|
|
77
|
+
file_name="logo.png",
|
|
78
|
+
file=file_bytes
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
# Or upload directly from a file-like object
|
|
82
|
+
with open("path/to/your/sound.mp3", "rb") as f:
|
|
83
|
+
bb.upload_asset(
|
|
84
|
+
app_id="my-app",
|
|
85
|
+
file_name="notification.mp3",
|
|
86
|
+
file=f
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Drawing on the Display
|
|
91
|
+
|
|
92
|
+
Draw text or images on the device's screen. The `draw_display` method accepts a list of elements to render.
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
elements = [
|
|
96
|
+
{
|
|
97
|
+
"type": "text",
|
|
98
|
+
"value": "Hello, World!",
|
|
99
|
+
"x": 10,
|
|
100
|
+
"y": 20,
|
|
101
|
+
"color": "#FFFFFF" # Optional
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"type": "image",
|
|
105
|
+
"path": "logo.png", # Must be uploaded first
|
|
106
|
+
"x": 50,
|
|
107
|
+
"y": 40
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
bb.draw_display(app_id="my-app", elements=elements)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Clearing the Display
|
|
115
|
+
|
|
116
|
+
To clear everything from the screen:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
bb.clear_display()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Playing a Sound
|
|
123
|
+
|
|
124
|
+
Play an audio file that you have already uploaded.
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
bb.play_sound(app_id="my-app", path="notification.mp3")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Stopping a Sound
|
|
131
|
+
|
|
132
|
+
To stop any audio that is currently playing:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
bb.stop_sound()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Deleting All Assets for an App
|
|
139
|
+
|
|
140
|
+
This will remove all files associated with a specific `app_id`.
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
bb.delete_assets(app_id="my-app")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
To set up a development environment, clone the repository and install the package in editable mode with test dependencies:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
git clone https://github.com/busy-app/busylib
|
|
152
|
+
cd busylib
|
|
153
|
+
python3 -m venv .venv
|
|
154
|
+
source .venv/bin/activate
|
|
155
|
+
make install-dev
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
To run the tests:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
make test
|
|
162
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
busylib/__init__.py,sha256=uxjPUviskpLD81tC5UqRFTTNr1jh7KkvPaKOnUivhFg,2605
|
|
2
|
+
busylib/client.py,sha256=725I_M8AdLUhDI3OjxSZe-giNQsA68lc5Sm1tBFIEJY,3728
|
|
3
|
+
busylib/types.py,sha256=LlBb1-lQraCjAitU-ImI52EXsayXCMcLvEjyuLXsABQ,176
|
|
4
|
+
busylib-0.0.1a0.dist-info/licenses/LICENSE,sha256=aJO9BQGuVb1fvGzHcgWYiwcC9kEFyD-FBb8SPO-ATJ4,1071
|
|
5
|
+
busylib-0.0.1a0.dist-info/METADATA,sha256=ryevnkeOa9xCku8ZdCn14mVJau_SqLbbAfG3jzP_Org,3826
|
|
6
|
+
busylib-0.0.1a0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
busylib-0.0.1a0.dist-info/top_level.txt,sha256=tXeqg2EVVj4E8-ywimkxRzuCJq2HqMXA0571IB15PDA,8
|
|
8
|
+
busylib-0.0.1a0.dist-info/RECORD,,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright © 2025 Flipper Devices Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
busylib-0.0.1.dist-info/METADATA
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: busylib
|
|
3
|
-
Version: 0.0.1
|
|
4
|
-
Summary: Package name reserved
|
|
5
|
-
Home-page: https://github.com/yourusername/busylib
|
|
6
|
-
Author: Your Name
|
|
7
|
-
Author-email: your.email@example.com
|
|
8
|
-
Classifier: Development Status :: 1 - Planning
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Requires-Python: >=3.6
|
|
11
|
-
Dynamic: author
|
|
12
|
-
Dynamic: author-email
|
|
13
|
-
Dynamic: classifier
|
|
14
|
-
Dynamic: description
|
|
15
|
-
Dynamic: home-page
|
|
16
|
-
Dynamic: requires-python
|
|
17
|
-
Dynamic: summary
|
|
18
|
-
|
|
19
|
-
This package name is reserved for future use
|
busylib-0.0.1.dist-info/RECORD
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
busylib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
busylib-0.0.1.dist-info/METADATA,sha256=Sv52rhD4zCfqKgPLYbddqmEiCJX7vUJ1MxYM-QxtexA,492
|
|
3
|
-
busylib-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
-
busylib-0.0.1.dist-info/top_level.txt,sha256=tXeqg2EVVj4E8-ywimkxRzuCJq2HqMXA0571IB15PDA,8
|
|
5
|
-
busylib-0.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|