4 releases (2 breaking)
0.3.0 | Jul 27, 2022 |
---|---|
0.2.0 | Jul 25, 2022 |
0.1.0-alpha.1 | Jul 21, 2022 |
0.1.0-alpha.0 | Jul 19, 2022 |
#735 in Hardware support
2MB
789 lines
ble-ledly
Customizable and extensible cross-platform high-level Bluetooth Low Energy light controller.
Provides out-of-the-box support for generic RGB led strips and BLE lamps and light bulbs. Designed to be extensible, allows to implement your own devices, communication protocol or both (See the readme file for more). Supports hardware specific animations (transferrable) and software non-transferrable animations.
Capabilities
Each device supports multiple capabilities available as featurs through conditional compilation in the .toml file.
ble-ledly = {version = "0.3", features = ["all"]}
Each capability provides a single point access to a specific device characteristic that can be manipulated through the publicly available set()
method. All the methods are available through the standard API Capability::set(opts)
or through more idiomatic methods as follow.
// standard
Light::set(light, &protocol, &LightOption::On).await?;
// idiomatic syntactic sugar
light.turn_on(&protocol).await?;
Capability | Description | Implemented? |
---|---|---|
Light |
Light state (on/off) | ✅ |
Color |
Light Color (RGB) | ✅ |
Brightness |
Light white levels | ✅ |
HWAnimate |
Hardware specific animations (subjected to protocol) | ✅ |
SWAnimate |
Software animation (require continuous communication, but allows custom effect on any device) | ✅ |
Temperature |
Light temperature (K) |
Animations
Transferrable vs. Non-transferrable
Transferrable animations are built-in in the target ble device which takes care of driving the led(s); once the command is sent, no extra communication needed between the client and ble light controller. Non-transferrable animations bypass the controller's built-in effects and allow for higher degree of customization while providing support for legacy or cheap light controllers allowing to provide effects otherwise not available to the target device. As a consequence, this requires continuous connection between the controller and client.
Current support
Animation | Capability | Color Support | Implemented? |
---|---|---|---|
Pulsating | HWAnimate | Red/Green/Blue | ✅ |
Breathing | SWAnimate | RGB/Any | ✅ |
Rainbow Pulsating | HWAnimate | N/A | |
Pulsating Bicolor | HWAnimate | Red/Green, Red/Blue, Green/Blue | |
Rainbow flashing | HWAnimate | N/A | |
Cross-fade | SWAnimate | RGB/Any | |
Rainbow jumping | HWAnimate | N/A | |
Flashing | HWAnimate | Red, Green, Blue, Yellow, Purple, Cyan |
Extensibility
This library has been designed with extensibility in mind.
- It is possible to create your own device by implementing the
Device
trait and use the built-in communication protocol. - You can add your own communication protocol by implementing the
Protocol
trait and use it to drive one of the built-in devices. - Create your own
device
andcommunication protocol
.
Usage
An example using built-in device LedDevice and GenericRGB communication protocol. For more examples, see the examples folder.
Minimal Configuration
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Create a new Light controller with prefix
// Auto-filter devices that contain the prefix
let mut controller = Controller::<LedDevice>::new_with_prefix("QHM-").await?;
// Connect
controller.connect().await?;
// Choose your communication protocol
let protocol = GenericRGB::default();
// set default write characteristic for all connected
// devices
controller.set_all_char(&CharKind::Write, &UuidKind::Uuid16(0xFFD9))?;
// Setting first found light color to red
let first_light = controller.list().get(0).unwrap();
first_light.color(&protocol, 255, 0, 0).await?;
Ok(())
}
Light controls
use ble_ledly::capability::color::*;
use ble_ledly::capability::light::*;
use ble_ledly::capability::sw_animate::*;
use ble_ledly::communication_protocol::GenericRGB;
use ble_ledly::Controller;
use ble_ledly::device::LedDevice;
use ble_ledly::device::{CharKind, UuidKind};
use std::error::Error;
use std::time::Duration;
use tokio::time;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
// Create a new Light controller
let mut controller = Controller::<LedDevice>::new().await?;
// Discover devices (scan)
let led_devices = controller.device_discovery().await?;
// inspect all found devices
for device in led_devices.iter() {
println!("Found device: {}", device);
}
// filter devices
let lights: Vec<LedDevice> = led_devices
.into_iter()
.filter(|device| device.name.contains("QHM-"))
.collect();
// Connect
controller.connect_with_devices(lights).await?;
// Choose your communication protocol
let protocol = GenericRGB::default();
// set the default write Characteristic
// for all devices. Optionally you can also
// set it per-device. Look the examples folder for more
controller.set_all_char(&CharKind::Write, &UuidKind::Uuid16(0xFFD9))?;
// list all connected devices
let connected_lights = controller.list();
for light in connected_lights.iter_mut() {
println!("Connected to : {}", light.name);
// Control the lights
println!("Turning light on...");
light.turn_on(&protocol).await?;
// Set color
println!("Setting color...");
light.color(&protocol, 255, 0, 0).await?;
time::sleep(Duration::from_millis(800)).await;
light.color(&protocol, 0, 255, 0).await?;
time::sleep(Duration::from_millis(800)).await;
light.color(&protocol, 0, 0, 255).await?;
time::sleep(Duration::from_millis(800)).await;
println!("SW Animation - Breathing effect...");
light
.breathing(
&GenericRGB {},
&ColorOption::RGB(255, 0, 0),
&SWAnimationRepeat::FiniteCount(2),
&SWAnimationSpeed::Fastest,
)
.await?;
light
.breathing(
&GenericRGB {},
&ColorOption::RGB(0, 255, 0),
&SWAnimationRepeat::FiniteCount(2),
&SWAnimationSpeed::Fastest,
)
.await?;
light
.breathing(
&GenericRGB {},
&ColorOption::RGB(0, 0, 255),
&SWAnimationRepeat::FiniteCount(2),
&SWAnimationSpeed::Fastest,
)
.await?;
// Control the lights
println!("Turning light off...");
light.turn_off(&protocol).await?;
}
Ok(())
}
Contributing
Open a PR or issue
License
MIT
Dependencies
~5–37MB
~506K SLoC