10 个版本
0.4.1 | 2023 年 5 月 23 日 |
---|---|
0.4.0 | 2022 年 6 月 30 日 |
0.4.0-rc.1 | 2021 年 12 月 30 日 |
0.3.0 | 2020 年 6 月 28 日 |
0.1.0 | 2020 年 6 月 16 日 |
#160 在 命令行界面
101 每月下载
用于 yeelight-cli
82KB
1.5K SLoC
Yeelight
本项目为 Yeelight Wi-Fi 灯互操作规范提供 Rust 绑定。
规范中指定的所有方法都已实现,并且名称与上述规范相同。
本项目可以作为二进制 crate 或带有 API 绑定的库供开发者使用。二进制 crate 提供一个 CLI 工具来控制灯光(这代替了 yeelight-cli)
目录
小米警告
!!! 不要更新小米品牌产品的灯泡固件 !!!
从 2021 年 1 月开始,小米品牌智能灯泡在更新固件时丢失了 LAN 控制功能,并且没有回滚选项。查看
CLI 使用
您可以通过安装并使用 cargo 或 cargo run 运行一个 CLI 来控制灯泡。程序名称将为 yeelight
cargo install yeelight
yeelight --help # or cargo run -- --help
有所有 yeelight API 规范的命令
yeelight 0.4.0
A CLI to control your Yeelight smart lights.
USAGE:
yeelight [OPTIONS] [address] <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-p, --port <port> [env: YEELIGHT_PORT=] [default: 55443]
-t, --timeout <timeout> [env: YEELIGHT_TIMEOUT=] [default: 5000]
ARGS:
<address> [env: YEELIGHT_ADDR=] [default: NULL]
SUBCOMMANDS:
adjust Adjust properties (Bright/CT/Color) (increase/decrease/circle)
adjust-percent Adjust properties (Bright/CT/Color) with percentage (-100~100)
discover
flow Start color flow
flow-stop Stop color flow
get Get properties
help Prints this message or the help of the given subcommand(s)
listen Listen to notifications from lamp
music-connect Connect to music TCP stream
music-stop Stop music mode
off Turn off light
on Turn on light
preset Presets
set Set values
timer Start timer
timer-clear Clear current timer
timer-get Get remaining minutes for timer
toggle Toggle light
指定灯具
唯一必需的参数是 <address>
,可以是 IP 地址、灯泡名称或值 all
- 如果提供了 IP 地址,
yeelight
将尝试连接到该地址上的灯泡;如果timeout
毫秒内无法建立连接,则将失败。 - 如果提供了名称,
yeelight
将发送发现消息并等待具有给定名称的灯泡响应。如果在timeout
毫秒内找不到此类灯泡,则操作将失败。 - 如果给出了特殊关键字
all
,则命令将在timeout
窗口内响应网络中所有发现消息的灯泡上运行。
此外,您可以设置环境变量 YEELIGHT_ADDR
来指定默认地址,如果未提供。
运行 discovery
命令时,无需指定地址,在其他所有情况下,必须提供地址。
子命令
有关每个子命令的功能和选项的详细信息,可以在每个子命令上发出 --help
。
库使用
用法非常直接,您可以使用内置的灯泡发现方法来定位灯泡并与它们连接。如果您事先知道地址,也可以直接连接。连接到灯泡后,您可以调用各种方法来更改其状态。
灯泡
Bulb
对象表示对单个灯的活跃连接。所有操作都是通过在这个对象上调用方法来执行的。
发现
连接
从发现的灯泡
您可以通过调用 discover::DiscoveredBulb
来将一个 Bulb
升级为一个 discover::DiscoveredBulb
,方法是调用 discover::DiscoveredBulb::connect
。
从地址
您可以使用 Bulb::connect
或使用 Bulb::attach
或 Bulb::attach_tokio
从活动 TCP 连接创建一个 Bulb
来通过地址和端口进行连接。
基本操作
您可以通过查看 Bulb
对象文档来查看所有可用的方法和它们的参数。
音乐模式
音乐模式实际上将现有连接升级为反向连接(灯泡连接到库),允许您发送命令而不会受到速率限制。
启动音乐模式将启动一个新的监听套接字,告诉灯泡连接到该套接字,然后关闭旧连接。使用库/您的项目运行的机器的 IP 地址作为主机。例如,192.168.5.23
。
注意
请确保使用 1.X 版本的 Tokio 才能正常工作。
流
实现细节
此 crate 功能齐全,可以使用惯用的 Rust 方法控制 Yeelight 智能灯泡。
异步
此 crate 使用 tokio
来管理与 LED 的所有连接。
背景光
背景光方法通过在方法名前添加前缀“bg_”与前景方法分开,例如在yeelight规范中。这意味着前景光有Bulb::set_power
,而背景对应方法有Bulb::bg_set_power
,依此类推。
未来可能会通过在支持的方法中添加isBackground
参数来改变这一情况。
功能
默认情况下,此crate使用所有功能。在某些情况下,如果空间最为关键,您可以在编译时省略一些功能以减小其影响。
目前只有2个不同的功能
- "from-str":此功能使能够从字符串中解析灯泡的响应和地址。
- "discovery":此功能使灯泡发现成为可能。
未来可能会添加另一个功能,完全移除tokio,使得在最小系统中也能使用此crate。然而,您可以使用不带async的0.2版本。
示例
所有示例也可以在examples
目录中找到。
柯拉茨
use std::{thread, time::Duration};
use yeelight::{Bulb, Effect, Mode, Power, Properties, Property};
// This program is meant to demonstrate some examples of commands and how to read the results turns
// on the bulb, changes the brightness following the collatz sequence (mod 100) 10 times waiting 1
// second each, and then sets the color to red over 10 seconds.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let mut bulb = Bulb::connect("192.168.1.204", 55443).await?;
// Turn on the bulb
println!(
"Response: {:?}",
bulb.set_power(
Power::On,
Effect::Sudden,
Duration::from_secs(1),
Mode::Normal
)
.await?
);
// Define flow array
let props = Properties(vec![
Property::Power,
Property::Bright,
Property::CT,
Property::RGB,
]);
for _ in 1..10u8 {
let response = bulb.get_prop(&props).await?.unwrap();
let brightness = response[1].parse::<u32>()?;
// Change brightness following collatz sequence
let brightness = if brightness % 2 == 0 {
brightness / 2
} else {
brightness * 3 + 1
};
// Make sure brightness is between 1 and 100.
let brightness = (brightness % 100 + 1) as u8;
println!("Setting brightness to {}", brightness);
// Change brightness
let response = bulb
.set_bright(brightness, Effect::Smooth, Duration::from_secs(1))
.await?;
eprintln!("Response: {:?}", response);
thread::sleep(Duration::from_secs(1));
}
// Set bulb to pure red over 10 seconds
bulb.set_rgb(0xff_00_00, Effect::Smooth, Duration::from_secs(1))
.await?;
Ok(())
}
流
use std::time::Duration;
use yeelight::{Bulb, CfAction, Effect, FlowExpresion, FlowTuple, Mode, Power};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let my_bulb_ip = "192.168.1.204";
let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;
// Turn on the bulb
let response = bulb
.set_power(Power::On, Effect::Sudden, Duration::new(0, 0), Mode::Normal)
.await?;
println!("response: {:?}", response);
// Define flow array
let flow = FlowExpresion(vec![
FlowTuple::ct(Duration::from_millis(500), 3000, 100),
FlowTuple::sleep(Duration::from_millis(1500)),
FlowTuple::ct(Duration::from_millis(500), 5000, 100),
FlowTuple::sleep(Duration::from_millis(1500)),
FlowTuple::ct(Duration::from_millis(500), 2600, 100),
FlowTuple::sleep(Duration::from_millis(1500)),
]);
// Send flow command
let response = bulb.start_cf(10, CfAction::Stay, flow).await?;
println!("response: {:?}", response);
Ok(())
}
音乐
use std::time::Duration;
use yeelight::{Bulb, Effect, Power, Mode};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let my_bulb_ip = "192.168.1.200";
let my_computer_ip = "192.168.1.23";
let mut bulb = Bulb::connect(my_bulb_ip, 0).await?;
let mut music_conn = bulb.start_music(my_computer_ip).await?;
let sleep_duration = Duration::from_millis(300);
let no_duration = Duration::from_millis(0);
bulb.set_power(Power::On, Effect::Sudden, no_duration, Mode::Normal).await?;
for _ in 0..60 {
std::thread::sleep(sleep_duration);
music_conn.set_rgb(0x00ff00, Effect::Sudden, no_duration).await?;
std::thread::sleep(sleep_duration);
music_conn.set_rgb(0x0000ff, Effect::Sudden, no_duration).await?;
std::thread::sleep(sleep_duration);
music_conn.set_rgb(0xff0000, Effect::Sudden, no_duration).await?;
}
drop(music_conn);
Ok(())
}
通知
use yeelight::Bulb;
#[tokio::main]
async fn main() {
env_logger::init();
let my_bulb_ip = "192.168.1.200";
let mut bulb = Bulb::connect(my_bulb_ip, 55443)
.await
.expect("Connection failed");
if let Some(response) = bulb.toggle().await.expect("Error") {
for v in response.iter() {
println!("{}", v);
}
}
}
属性
use std::time::Duration;
use yeelight::{Bulb, Effect, Mode, Power, Properties, Property};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let my_bulb_ip = "192.168.1.204";
let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;
// Turn on the bulb
println!(
"Response: {:?}",
bulb.set_power(
Power::On,
Effect::Sudden,
Duration::from_millis(0),
Mode::Normal
)
.await?
);
// Define flow array
let props = Properties(vec![
Property::Power,
Property::Bright,
Property::CT,
Property::RGB,
]);
// Send flow command
println!("Response: {:?}", bulb.get_prop(&props).await?);
println!(
"Response: {:?}",
bulb.set_rgb(122, Effect::Smooth, Duration::from_millis(500))
.await?
);
Ok(())
}
切换
use yeelight::Bulb;
#[tokio::main]
async fn main() {
env_logger::init();
let mut bulb = Bulb::connect(my_bulb_ip, 55443)
.await
.expect("Connection failed");
if let Some(response) = bulb.toggle().await.expect("Error") {
for v in response.iter() {
println!("{}", v);
}
}
}
路线图
目前所有主要API功能都已实现,仅计划对API的可用性进行更改。不过,计划中的更改可能会引入破坏性更改。
API 功能
- 实现所有API函数
- 处理灯泡响应
- 在网络中发现灯泡
- 监听灯泡通知
生活质量
- 移除[CronType]?
- 灯泡响应超时
- 更改处理背景LED的方式
- 合并[Effect]和
Duration
参数 - 使音乐工作流程更易用
- 处理灯泡组
测试
- 涵盖所有主要方法
故障排除
连接被拒绝
错误:操作系统{代码: 111,类型:连接被拒绝,消息: "连接拒绝" }
- 请确保关闭正在运行的VPN。
无效参数
错误:响应错误(-5001, "无效参数")
- 在Yeelight/Mi Home应用上关闭音乐流。
速率限制
- 开启音乐模式
依赖项
~5–14MB
~167K SLoC