|
1 | 1 | # vudials_client |
2 | 2 |
|
3 | 3 | [](https://badge.fury.io/py/vudials_client) |
| 4 | +[](https://github.com/erinlkolp/vu1-dial-python-module/actions/workflows/ci.yml) |
4 | 5 | [](https://opensource.org/licenses/MIT) |
| 6 | +[](https://www.python.org/downloads/) |
5 | 7 |
|
6 | | -A Python client module for Streacom's VU1 Dial development hardware. This provides a simple interface to manipulate multiple dials. |
| 8 | +A Python client library for Streacom's VU1 Dial development hardware. Provides a simple, tested interface for controlling multiple dials and managing the VU1 server. |
7 | 9 |
|
8 | 10 | ## Features |
9 | 11 |
|
10 | | -- **Full Dial API**: Easily change your dial's value, color, name, background image, and more! |
11 | | -- **Full Admin API**: Provides VU1 Dial Server API key management. |
| 12 | +- **Full Dial API**: Change a dial's value, backlight color, name, background image, and easing parameters |
| 13 | +- **Full Admin API**: VU1 Dial Server API key management and dial provisioning |
| 14 | +- **Type-annotated**: All public methods carry full parameter and return-type annotations |
| 15 | +- **Well tested**: Comprehensive test suite using `pytest` and `responses` — no live hardware required |
| 16 | +- **CI tested**: Passes on Python 3.11, 3.12, and 3.13 via GitHub Actions |
12 | 17 |
|
13 | 18 | ## Installation |
14 | 19 |
|
15 | 20 | ```bash |
16 | 21 | pip install vudials-client |
17 | 22 | ``` |
18 | 23 |
|
19 | | -For development installation: |
| 24 | +For development: |
20 | 25 |
|
21 | 26 | ```bash |
22 | 27 | git clone git@github.com:erinlkolp/vu1-dial-python-module.git |
23 | | -cd vu1-dial-python-module/ |
| 28 | +cd vu1-dial-python-module |
24 | 29 | pip install -e ".[dev]" |
25 | 30 | ``` |
26 | 31 |
|
27 | 32 | ## Quick Start |
28 | 33 |
|
29 | | -Here's a simple example to get you started: |
30 | | - |
31 | 34 | ```python |
| 35 | +import os |
32 | 36 | from vudials_client import vudialsclient |
33 | 37 |
|
34 | | -server_key = os.environ['API_KEY'] |
35 | | -admin_key = os.environ['ADMIN_API_KEY'] |
36 | | -server_address = os.environ['VU1_SERVER_ADDRESS'] |
37 | | -server_port = os.environ['VU1_SERVER_PORT'] |
| 38 | +server_address = os.environ["VU1_SERVER_ADDRESS"] |
| 39 | +server_port = int(os.environ["VU1_SERVER_PORT"]) |
| 40 | +server_key = os.environ["API_KEY"] |
| 41 | +admin_key = os.environ["ADMIN_API_KEY"] |
38 | 42 |
|
39 | 43 | vu_meter = vudialsclient.VUDial(server_address, server_port, server_key) |
40 | | -admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key) |
| 44 | +admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key) |
41 | 45 |
|
| 46 | +# List connected dials |
42 | 47 | dial_list = vu_meter.list_dials() |
43 | | -print(dial_list) |
| 48 | +print(dial_list.json()) |
| 49 | + |
| 50 | +# Set first dial to 75% with a blue backlight |
| 51 | +uid = dial_list.json()[0]["uid"] |
| 52 | +vu_meter.set_dial_value(uid, 75) |
| 53 | +vu_meter.set_dial_color(uid, 0, 0, 255) |
44 | 54 |
|
| 55 | +# List API keys |
45 | 56 | api_key_list = admin_api.list_api_keys() |
46 | | -print(api_key_list) |
| 57 | +print(api_key_list.json()) |
47 | 58 | ``` |
48 | 59 |
|
49 | | -## Documentation |
50 | | - |
51 | | -For detailed documentation, see [the official documentation](https://github.com/erinlkolp/vu1-dial-python-module/blob/main/docs/api.md). |
| 60 | +> **Note:** The VU1 server communicates over plain HTTP on your local network. Keep the server on a trusted interface and treat the API keys as secrets. Both keys are passed as URL query parameters and will appear in server access logs. |
52 | 61 |
|
53 | | -### Main Classes |
| 62 | +## API Reference |
54 | 63 |
|
55 | | -#### `VUDial` |
| 64 | +### `VUDial` |
56 | 65 |
|
57 | | -The primary class for interacting with the client-side module. |
| 66 | +Controls dial hardware. All methods return a `requests.Response`; HTTP 4xx/5xx errors raise `requests.exceptions.HTTPError`. |
58 | 67 |
|
59 | 68 | ```python |
60 | | -vu_meter = vudialsclient.VUDial(server_address, server_port, api_key) |
| 69 | +vu_meter = vudialsclient.VUDial(server_address, server_port, api_key) |
61 | 70 | ``` |
62 | 71 |
|
63 | | -**Parameters:** |
64 | | -- `server_address` (str): VU1 Dials Server host (ie. localhost) |
65 | | -- `server_port` (int): VU1 Dials Server port (ie. 5340) |
66 | | -- `api_key` (str): A valid API key for the VU1 Dials Server |
| 72 | +| Parameter | Type | Description | |
| 73 | +|---|---|---| |
| 74 | +| `server_address` | `str` | VU1 server hostname or IP (e.g. `"localhost"`) | |
| 75 | +| `server_port` | `int` | VU1 server port (e.g. `5340`) | |
| 76 | +| `api_key` | `str` | A valid API key for the VU1 server | |
67 | 77 |
|
68 | 78 | **Methods:** |
69 | | -- `list_dials()`: Processes the given data and returns a result |
70 | | -- `get_dial_info(uid)`: Saves the current state to a file |
71 | | -- `set_dial_value(uid, value)`: Sets a dial's value (position) |
72 | | -- `set_dial_color(uid, red, green, blue)`: Sets a dial's backlight color |
73 | | -- `set_dial_background(uid, file)`: Sets a dial's background image |
74 | | -- `get_dial_image_crc(uid)`: Obtains a dial's image CRC |
75 | | -- `set_dial_name(uid, name)`: Sets a dial's name (no spaces) |
76 | | -- `reload_hw_info(uid)`: Reloads dial hardware information |
77 | | -- `set_dial_easing(uid, period, step)`: Sets dial easing |
78 | | -- `set_backlight_easing(uid, period, step)`: Sets dial easing |
79 | | -- `get_easing_config(uid)`: Gets easing config for dial (unsupported as of now) |
80 | | - |
81 | | -#### `VUAdmin` |
82 | | - |
83 | | -The primary class for interacting with the client-side module. |
| 79 | + |
| 80 | +| Method | Description | |
| 81 | +|---|---| |
| 82 | +| `list_dials()` | List all connected dials | |
| 83 | +| `get_dial_info(uid)` | Get status/info for a specific dial | |
| 84 | +| `set_dial_value(uid, value)` | Set the dial position (0–100) | |
| 85 | +| `set_dial_color(uid, red, green, blue)` | Set the backlight color (0–255 each channel) | |
| 86 | +| `set_dial_background(uid, file)` | Upload a background image file | |
| 87 | +| `get_dial_image_crc(uid)` | Get the CRC of the current background image | |
| 88 | +| `set_dial_name(uid, name)` | Assign a name to a dial | |
| 89 | +| `reload_hw_info(uid)` | Reload hardware information for a dial | |
| 90 | +| `set_dial_easing(uid, period, step)` | Configure dial movement easing | |
| 91 | +| `set_backlight_easing(uid, period, step)` | Configure backlight easing | |
| 92 | +| `get_easing_config(uid)` | Retrieve current easing configuration | |
| 93 | + |
| 94 | +### `VUAdmin` |
| 95 | + |
| 96 | +Manages the VU1 server. All methods return a `requests.Response`; HTTP 4xx/5xx errors raise `requests.exceptions.HTTPError`. |
84 | 97 |
|
85 | 98 | ```python |
86 | | -admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key) |
| 99 | +admin_api = vudialsclient.VUAdmin(server_address, server_port, admin_key) |
87 | 100 | ``` |
88 | 101 |
|
89 | | -**Parameters:** |
90 | | -- `server_address` (str): VU1 Dials Server host (ie. localhost) |
91 | | -- `server_port` (int): VU1 Dials Server port (ie. 5340) |
92 | | -- `admin_key` (str): A valid Admin API key for the VU1 Dials Server |
| 102 | +| Parameter | Type | Description | |
| 103 | +|---|---|---| |
| 104 | +| `server_address` | `str` | VU1 server hostname or IP | |
| 105 | +| `server_port` | `int` | VU1 server port | |
| 106 | +| `admin_key` | `str` | A valid Admin API key for the VU1 server | |
93 | 107 |
|
94 | 108 | **Methods:** |
95 | | -- `provision_dials()`: Provisions new dial hardware |
96 | | -- `list_api_keys()`: Lists all VU Server API keys |
97 | | -- `remove_api_key(target_key)`: Removes an API key |
98 | | -- `create_api_key(name, dials)`: Creates an API key (see value in return) |
99 | | -- `update_api_key(name, target_key, dials)`: Updates an API key |
100 | 109 |
|
101 | | -## Contributing |
| 110 | +| Method | Description | |
| 111 | +|---|---| |
| 112 | +| `provision_dials()` | Provision newly connected dial hardware | |
| 113 | +| `list_api_keys()` | List all configured API keys | |
| 114 | +| `create_api_key(name, dials)` | Create a new API key; the generated key is in the response | |
| 115 | +| `update_api_key(name, target_key, dials)` | Update an existing API key | |
| 116 | +| `remove_api_key(target_key)` | Remove an API key | |
102 | 117 |
|
103 | | -Contributions are welcome! Please feel free to submit a Pull Request. |
| 118 | +## Testing |
104 | 119 |
|
105 | | -1. Fork the repository |
106 | | -2. Create your feature branch (`git checkout -b feature/amazing-feature`) |
107 | | -3. Commit your changes (`git commit -m 'Add some amazing feature'`) |
108 | | -4. Push to the branch (`git push origin feature/amazing-feature`) |
109 | | -5. Open a Pull Request |
| 120 | +The test suite uses [`responses`](https://github.com/getsentry/responses) to mock all HTTP calls — no VU1 hardware or running server is required. |
110 | 121 |
|
111 | | -Please make sure to update tests as appropriate and follow the code style guide. |
| 122 | +```bash |
| 123 | +# Run all tests with coverage report |
| 124 | +pytest tests/ -v --cov=vudials_client --cov-report=term-missing |
112 | 125 |
|
113 | | -## License |
| 126 | +# Run a specific test class |
| 127 | +pytest tests/test_vudialsclient.py::TestVUDialSetDialColor -v |
| 128 | +``` |
| 129 | + |
| 130 | +CI runs automatically on every push and pull request via GitHub Actions across Python 3.11, 3.12, and 3.13. |
114 | 131 |
|
115 | | -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
| 132 | +## Documentation |
116 | 133 |
|
117 | | -## Acknowledgements |
| 134 | +Full API documentation can be regenerated from docstrings: |
118 | 135 |
|
119 | | -- Many thanks to Aaron D. and Christopher K.! |
| 136 | +```bash |
| 137 | +pip install pydoc-markdown |
| 138 | +pydoc-markdown |
| 139 | +``` |
120 | 140 |
|
121 | | -## License & Author |
| 141 | +This writes `docs/api.md` using the configuration in `pydoc-markdown.yml`. |
122 | 142 |
|
123 | | -- Author:: Erin L. Kolp (<erinlkolpfoss@gmail.com>) |
| 143 | +## Contributing |
124 | 144 |
|
125 | | -Copyright (c) 2025 Erin L. Kolp |
| 145 | +Contributions are welcome! Please open a pull request. |
| 146 | + |
| 147 | +1. Fork the repository |
| 148 | +2. Create a feature branch (`git checkout -b feature/my-feature`) |
| 149 | +3. Make your changes and add tests for any new or modified behaviour |
| 150 | +4. Ensure the test suite passes: `pytest tests/ -v` |
| 151 | +5. Open a pull request against `main` |
| 152 | + |
| 153 | +Please follow the existing code style: type-annotate all public methods, URL-encode user-supplied path segments with `quote(value, safe="")`, and keep library code free of `logging.basicConfig()` calls. |
| 154 | + |
| 155 | +## License |
126 | 156 |
|
127 | | -Licensed under the MIT License |
| 157 | +MIT — see [LICENSE](LICENSE). |
128 | 158 |
|
129 | | -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 |
130 | | -permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 159 | +## Author |
131 | 160 |
|
132 | | -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
| 161 | +Erin L. Kolp (<erinlkolpfoss@gmail.com>) |
133 | 162 |
|
134 | | -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. |
| 163 | +Many thanks to Aaron D. and Christopher K.! |
0 commit comments