Using the Async SignalRGB Client
Starting from version 1.0.0, signalrgb-python includes a native asyncio-based client that allows you to integrate SignalRGB functionality with async code. This is particularly useful for applications built on asyncio, such as Home Assistant integrations or asynchronous web applications.
🚀 Basic Usage
The AsyncSignalRGBClient
provides the same functionality as the synchronous client but with async/await syntax:
import asyncio
from signalrgb import AsyncSignalRGBClient
async def main():
# Create a client
async with AsyncSignalRGBClient() as client:
# Get current effect
effect = await client.get_current_effect()
print(f"Current effect: {effect.attributes.name}")
# List available effects
effects = await client.get_effects()
print(f"Available effects: {len(effects)}")
# Apply a random effect
new_effect = await client.apply_random_effect()
print(f"Applied effect: {new_effect.attributes.name}")
# Run the async code
asyncio.run(main())
📊 Comparison with Synchronous Client
The async client provides the same functionality as the synchronous client but with async/await syntax:
Synchronous Client | Asynchronous Client |
---|---|
client.get_effects() |
await client.get_effects() |
client.apply_effect(id) |
await client.apply_effect(id) |
client.brightness = 50 |
await client.set_brightness(50) |
client.enabled = True |
await client.set_enabled(True) |
🔄 Properties vs Methods
Unlike the synchronous client, the asynchronous client uses methods instead of properties for read/write operations, since properties in Python can't be async:
Synchronous Client | Asynchronous Client |
---|---|
client.brightness |
await client.get_brightness() |
client.brightness = 50 |
await client.set_brightness(50) |
client.enabled |
await client.get_enabled() |
client.enabled = True |
await client.set_enabled(True) |
client.current_layout |
await client.get_current_layout() |
client.current_layout = "layout" |
await client.set_current_layout("layout") |
🏠 Integration with Home Assistant
The async client is particularly well-suited for integrating with Home Assistant, which uses asyncio for its operations:
from homeassistant.components.light import LightEntity
from signalrgb import AsyncSignalRGBClient
class SignalRGBLight(LightEntity):
def __init__(self, client):
self._client = client
self._name = "SignalRGB"
self._state = False
self._brightness = 0
async def async_turn_on(self, **kwargs):
await self._client.set_enabled(True)
if "brightness" in kwargs:
# Home Assistant brightness is 0-255, SignalRGB is 0-100
brightness = round(kwargs["brightness"] / 255 * 100)
await self._client.set_brightness(brightness)
self._state = True
async def async_turn_off(self, **kwargs):
await self._client.set_enabled(False)
self._state = False
async def async_update(self):
self._state = await self._client.get_enabled()
self._brightness = await self._client.get_brightness()
See the examples/home_assistant_example.py
file for a more complete Home Assistant integration example.
📦 Context Manager Support
The async client supports being used as an async context manager, which ensures proper cleanup of resources:
async with AsyncSignalRGBClient() as client:
# client is automatically closed when exiting this block
await client.get_effects()
You can also manually close the client:
🛡️ Error Handling
The async client raises the same exceptions as the synchronous client. Always use try/except blocks to catch and handle potential errors:
try:
await client.apply_effect_by_name("nonexistent_effect")
except NotFoundError:
print("Effect not found")
except ConnectionError:
print("Connection error")
except APIError as e:
print(f"API error: {e}")
🔄 Backward Compatibility
The synchronous client is still available and fully functional. In fact, it now uses the async client internally, running operations in a synchronized manner. This allows existing code to continue working without changes.
If you're using the client in a synchronous context but need to call it from async code in some places, you can mix approaches:
# In synchronous code
from signalrgb import SignalRGBClient
client = SignalRGBClient()
effects = client.get_effects()
# Later, in an async context
async def async_function():
# Use the async client directly
async with AsyncSignalRGBClient() as async_client:
await async_client.apply_effect_by_name("some_effect")
🚀 Performance Considerations
The async client can offer better performance in async applications, especially when:
- Making multiple concurrent requests
- Integrating with other async code like Home Assistant
- Operating in event-loop based applications
- Processing many effects/devices simultaneously
It avoids blocking the event loop while waiting for API responses, allowing your application to remain responsive while processing SignalRGB operations.
💡 Advanced Example: Effect Cycling
Here's a more advanced example that cycles through all available effects, displaying each for a specified duration:
import asyncio
from signalrgb import AsyncSignalRGBClient
async def cycle_effects(duration=5):
"""Cycle through all effects, displaying each for the specified duration."""
async with AsyncSignalRGBClient() as client:
effects = await client.get_effects()
print(f"Cycling through {len(effects)} effects...")
for effect in effects:
print(f"Applying effect: {effect.attributes.name}")
await client.apply_effect(effect.id)
await asyncio.sleep(duration)
if __name__ == "__main__":
asyncio.run(cycle_effects(duration=3))
This example demonstrates how to leverage the async capabilities to create a non-blocking effect showcase application.