{"id":33927399,"url":"https://github.com/leixb/yeelight","last_synced_at":"2025-12-12T11:00:07.585Z","repository":{"id":45202288,"uuid":"271899738","full_name":"Leixb/yeelight","owner":"Leixb","description":"Rust API bindings for yeelight WiFi Light Inter-Operation","archived":false,"fork":false,"pushed_at":"2024-05-14T19:24:15.000Z","size":212,"stargazers_count":20,"open_issues_count":7,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-06T16:58:43.280Z","etag":null,"topics":["api-wrapper","rust","yeelight"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Leixb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-12T22:19:24.000Z","updated_at":"2025-01-05T14:02:33.000Z","dependencies_parsed_at":"2024-05-15T12:42:27.156Z","dependency_job_id":"e352e4b0-d26a-4f20-9733-8df6584186fa","html_url":"https://github.com/Leixb/yeelight","commit_stats":{"total_commits":121,"total_committers":3,"mean_commits":"40.333333333333336","dds":"0.024793388429752095","last_synced_commit":"f0d1c223422cd0dd383f4ce38de7268237dc0c45"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/Leixb/yeelight","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leixb%2Fyeelight","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leixb%2Fyeelight/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leixb%2Fyeelight/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leixb%2Fyeelight/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Leixb","download_url":"https://codeload.github.com/Leixb/yeelight/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Leixb%2Fyeelight/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27681552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-wrapper","rust","yeelight"],"created_at":"2025-12-12T11:00:06.496Z","updated_at":"2025-12-12T11:00:07.579Z","avatar_url":"https://github.com/Leixb.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Yeelight\n[![built with nix](https://img.shields.io/static/v1?logo=nixos\u0026logoColor=white\u0026label=\u0026message=Built%20with%20Nix\u0026color=41439a)](https://builtwithnix.org \"built with nix\")\n[![build](https://github.com/Leixb/yeelight/actions/workflows/rust.yml/badge.svg)](https://github.com/Leixb/yeelight/actions/workflows/rust.yml)\n\nThis project provides Rust bindings for the [Yeelight Wi-Fi Light Interoperation Specification][1].\n\nAll the methods specified in the spec are implemented and named equally to the\naforementioned specification.\n\nThis project can be used both as a binary crate or as library with API bindings\nfor developers. The binary crate provides a CLI tool to control lights (this\nreplaces [yeelight-cli][2])\n\n## Table of Contents\n- [CLI Usage](#cli-usage)\n- [Library Usage](#library-usage)\n  - [Bulb](#bulb)\n  - [Discovery](#discovery)\n  - [Connection](#connection)\n    - [From discovered bulbs](#from-discovered-bulbs)\n    - [From address](#from-address)\n  - [Basic Operations](#basic-operations)\n  - [Music Mode](#music-mode)\n  - [Flows](#flows)\n- [Implementation](#implementation-details)\n  - [Async](#async)\n  - [Background light](#background-light)\n  - [Features](#features)\n- [Examples](#examples)\n  - [Collatz](#collatz)\n  - [Flow](#flow)\n  - [Music](#music)\n  - [Notification](#notification)\n  - [Properties](#properties)\n  - [Toggle](#toggle)\n- [Roadmap](#roadmap)\n  - [API features](#api-features)\n  - [Quality of life](#quality-of-life)\n  - [Testing](#testing)\n- [Troubleshooting](#troubleshooting)\n  - [Connection refused](#connection-refused)\n  - [Invalid params](#invalid-params)\n\n\n## Xiaomi warning\n\n**!!! Do NOT update your light firmware of Xiaomi branded products !!!**\n\nStarting January 2021, Xiaomi branded smart lights lost their LAN control\nfunctionality when updating firmware with no option to rollback.\n[see](https://twitter.com/home_assistant/status/1376789260611637251)\n\n## CLI Usage\n\nYou can run a cli to control lights from by installing it with cargo or using\ncargo run. The program name will be `yeelight`:\n\n```bash\ncargo install yeelight\nyeelight --help # or cargo run -- --help\n```\n\nThere are commands for all yeelight API specs:\n\n```\nyeelight 0.4.0\nA CLI to control your Yeelight smart lights.\n\nUSAGE:\n    yeelight [OPTIONS] [address] \u003cSUBCOMMAND\u003e\n\nFLAGS:\n    -h, --help       Prints help information\n    -V, --version    Prints version information\n\nOPTIONS:\n    -p, --port \u003cport\u003e           [env: YEELIGHT_PORT=]  [default: 55443]\n    -t, --timeout \u003ctimeout\u003e     [env: YEELIGHT_TIMEOUT=]  [default: 5000]\n\nARGS:\n    \u003caddress\u003e     [env: YEELIGHT_ADDR=]  [default: NULL]\n\nSUBCOMMANDS:\n    adjust            Adjust properties (Bright/CT/Color) (increase/decrease/circle)\n    adjust-percent    Adjust properties (Bright/CT/Color) with percentage (-100~100)\n    discover          \n    flow              Start color flow\n    flow-stop         Stop color flow\n    get               Get properties\n    help              Prints this message or the help of the given subcommand(s)\n    listen            Listen to notifications from lamp\n    music-connect     Connect to music TCP stream\n    music-stop        Stop music mode\n    off               Turn off light\n    on                Turn on light\n    preset            Presets\n    set               Set values\n    timer             Start timer\n    timer-clear       Clear current timer\n    timer-get         Get remaining minutes for timer\n    toggle            Toggle light\n```\n\n### Specifying the lamp\n\nThe only required argument is `\u003caddress\u003e` which can be either an IP address, the\nname of a lamp, or the value `all`:\n\n- If an IP address is provided, `yeelight`\n  will attempt to connect with a bulb on that address, if `timeout` milliseconds\n  pass and a connection cannot be established, it will fail.\n- If a name is provided, `yeelight` will launch a discovery message and wait\n  for a bulb with the given name to respond. If such bulb is not found in `timeout`\n  milliseconds, it will fail.\n- If the special keyword `all` is given, the command will be run on all the\n  bulbs that respond to a discovery message on the network in the given `timeout`\n  window.\n\nAdditionally, you can set the environment variable `YEELIGHT_ADDR` to specify\nthe default address if none is provided.\n\nWhen running the `discovery` command, there is no need to specify the address,\nin all other cases, an address must be provided.\n\n### Subcommands\n\nDetails on the functionality and options of each command can be seen by issuing\n`--help` on each subcommand.\n\n## Library Usage\n\nThe usage is quite straight forward, you can use the built-in bulb discovery\nmethod to locate the Bulbs and connect to them. You can also connect directly\nif you know the address beforehand. Once connected to the Bulb you can call the\nvarious methods to change its status.\n\n### Bulb\n\nThe [`Bulb`] object represents an active connection to a singular light. All\noperations are applied through calling methods on this object.\n\n### Discovery\n\n### Connection\n\n#### From discovered Bulbs\n\nYou can \"upgrade\" a [`discover::DiscoveredBulb`] to a [`Bulb`] by calling\n[`discover::DiscoveredBulb::connect`].\n\n#### From address\n\nYou can connect using an address and port using [`Bulb::connect`] or create a\n[`Bulb`] from an active TCP connection using [`Bulb::attach`] or [`Bulb::attach_tokio`].\n\n### Basic operations\n\nYou can refer to the `Bulb` object documentation to view all the methods\navailable and their parameters.\n\n### Music Mode\nMusic mode essentially upgrades the existing connection to a reverse one (the bulb connects to the library), allowing you to send commands without being rate-limited.\n\nStarting music mode will start a new listening socket, tell the bulb to connect to that, and then close the old connection. Use the IP address of the machine where the library/your project runs as the host. (e.g., `192.168.5.23`).\n\n#### Note\nMake sure to use a 1.X version of Tokio for this to work.\n\n### Flows\n\n## Implementation details\n\nThis crate is feature complete and can be used to control Yeelight smart bulbs\nwith idiomatic Rust methods.\n\n### Async\n\nThis crate uses `tokio` to manage all connections with the LEDs.\n\n### Background light\n\nThe background light methods are separated from the foreground methods by\nprefixing the methods with `bg_` like in the yeelight spec. Meaning that there\nis [`Bulb::set_power`] for the foreground light and [`Bulb::bg_set_power`] for its background\ncounterpart and so on.\n\nThis may change in the future by adding a `isBackground` parameter to the\nsupported methods.\n\n### Features\n\nBy default this crate uses all it's features. In some cases where the space is\nmost crucial you can compile this crate without some of them to reduce it's\nimpact.\n\nCurrently there are only 2 different features:\n\n- \"from-str\": This enables parsing responses from the bulb and addresses from\n  strings.\n- \"discovery\": This enables Bulb discovery.\n\nIn the future there may be another feature removing tokio altogether allowing\nto use the crate in minimal systems. However you can use the 0.2 version of the\ncrate which does not have async.\n\n## Examples\nAll examples can also be found in the `examples` directory.\n\n### Collatz\n```rust\nuse std::{thread, time::Duration};\n\nuse yeelight::{Bulb, Effect, Mode, Power, Properties, Property};\n\n// This program is meant to demonstrate some examples of commands and how to read the results turns\n// on the bulb, changes the brightness following the collatz sequence (mod 100) 10 times waiting 1\n// second each, and then sets the color to red over 10 seconds.\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n\n    env_logger::init();\n\n    let mut bulb = Bulb::connect(\"192.168.1.204\", 55443).await?;\n\n    // Turn on the bulb\n    println!(\n        \"Response: {:?}\",\n        bulb.set_power(\n            Power::On,\n            Effect::Sudden,\n            Duration::from_secs(1),\n            Mode::Normal\n        )\n        .await?\n    );\n\n    // Define flow array\n    let props = Properties(vec![\n        Property::Power,\n        Property::Bright,\n        Property::Ct,\n        Property::Rgb,\n    ]);\n\n    for _ in 1..10u8 {\n        let response = bulb.get_prop(\u0026props).await?.unwrap();\n        let brightness = response[1].parse::\u003cu32\u003e()?;\n\n        // Change brightness following collatz sequence\n        let brightness = if brightness % 2 == 0 {\n            brightness / 2\n        } else {\n            brightness * 3 + 1\n        };\n\n        // Make sure brightness is between 1 and 100.\n        let brightness = (brightness % 100 + 1) as u8;\n        println!(\"Setting brightness to {}\", brightness);\n\n        // Change brightness\n        let response = bulb\n            .set_bright(brightness, Effect::Smooth, Duration::from_secs(1))\n            .await?;\n        eprintln!(\"Response: {:?}\", response);\n\n        thread::sleep(Duration::from_secs(1));\n    }\n\n    // Set bulb to pure red over 10 seconds\n    bulb.set_rgb(0xff_00_00, Effect::Smooth, Duration::from_secs(1))\n        .await?;\n    Ok(())\n}\n```\n\n### Flow\n```rust\nuse std::time::Duration;\n\nuse yeelight::{Bulb, CfAction, Effect, FlowExpresion, FlowTuple, Mode, Power};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n\n    env_logger::init();\n\n    let my_bulb_ip = \"192.168.1.204\";\n    let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;\n\n    // Turn on the bulb\n    let response = bulb\n        .set_power(Power::On, Effect::Sudden, Duration::new(0, 0), Mode::Normal)\n        .await?;\n    println!(\"response: {:?}\", response);\n\n    // Define flow array\n    let flow = FlowExpresion(vec![\n        FlowTuple::ct(Duration::from_millis(500), 3000, 100),\n        FlowTuple::sleep(Duration::from_millis(1500)),\n        FlowTuple::ct(Duration::from_millis(500), 5000, 100),\n        FlowTuple::sleep(Duration::from_millis(1500)),\n        FlowTuple::ct(Duration::from_millis(500), 2600, 100),\n        FlowTuple::sleep(Duration::from_millis(1500)),\n    ]);\n    // Send flow command\n    let response = bulb.start_cf(10, CfAction::Stay, flow).await?;\n    println!(\"response: {:?}\", response);\n    Ok(())\n}\n```\n\n### Music\n```rust\nuse std::time::Duration;\n\nuse yeelight::{Bulb, Effect, Power, Mode};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n\n    env_logger::init();\n\n    let my_bulb_ip = \"192.168.1.200\";\n    let my_computer_ip = \"192.168.1.23\";\n\n    let mut bulb = Bulb::connect(my_bulb_ip, 0).await?;\n    let mut music_conn = bulb.start_music(my_computer_ip).await?;\n\n    let sleep_duration = Duration::from_millis(300);\n    let no_duration = Duration::from_millis(0);\n\n    bulb.set_power(Power::On, Effect::Sudden, no_duration, Mode::Normal).await?;\n\n    for _ in 0..60 { \n        std::thread::sleep(sleep_duration);\n        music_conn.set_rgb(0x00ff00, Effect::Sudden, no_duration).await?;\n        std::thread::sleep(sleep_duration);\n        music_conn.set_rgb(0x0000ff, Effect::Sudden, no_duration).await?;\n        std::thread::sleep(sleep_duration);\n        music_conn.set_rgb(0xff0000, Effect::Sudden, no_duration).await?;\n    }\n\n    drop(music_conn);\n\n    Ok(())\n}\n```\n\n### Notification\n```rust\nuse yeelight::Bulb;\n\n#[tokio::main]\nasync fn main() {\n\n    env_logger::init();\n\n    let my_bulb_ip = \"192.168.1.200\";\n    let mut bulb = Bulb::connect(my_bulb_ip, 55443)\n        .await\n        .expect(\"Connection failed\");\n    if let Some(response) = bulb.toggle().await.expect(\"Error\") {\n        for v in response.iter() {\n            println!(\"{}\", v);\n        }\n    }\n}\n```\n\n### Properties\n```rust\nuse std::time::Duration;\n\nuse yeelight::{Bulb, Effect, Mode, Power, Properties, Property};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n\n    env_logger::init();\n\n    let my_bulb_ip = \"192.168.1.204\";\n    let mut bulb = Bulb::connect(my_bulb_ip, 55443).await?;\n\n    // Turn on the bulb\n    println!(\n        \"Response: {:?}\",\n        bulb.set_power(\n            Power::On,\n            Effect::Sudden,\n            Duration::from_millis(0),\n            Mode::Normal\n        )\n        .await?\n    );\n\n    // Define flow array\n    let props = Properties(vec![\n        Property::Power,\n        Property::Bright,\n        Property::Ct,\n        Property::Rgb,\n    ]);\n    // Send flow command\n    println!(\"Response: {:?}\", bulb.get_prop(\u0026props).await?);\n    println!(\n        \"Response: {:?}\",\n        bulb.set_rgb(122, Effect::Smooth, Duration::from_millis(500))\n            .await?\n    );\n    Ok(())\n}\n```\n\n### Toggle\n```rust\nuse yeelight::Bulb;\n\n#[tokio::main]\nasync fn main() {\n\n    env_logger::init();\n\n    let mut bulb = Bulb::connect(my_bulb_ip, 55443)\n        .await\n        .expect(\"Connection failed\");\n    if let Some(response) = bulb.toggle().await.expect(\"Error\") {\n        for v in response.iter() {\n            println!(\"{}\", v);\n        }\n    }\n}\n```\n\n## Roadmap\n\nCurrently all main API features are implemented and only changes on the\nusability of the API are planned. Nonetheless the planned changes may introduce\nbreaking changes.\n\n### API features\n- [x] Implement all API functions\n- [x] Process bulb responses\n- [x] Discover Bulbs in the network\n- [x] Listen to Bulb notifications\n\n### Quality of life\n- [ ] Remove [CronType]?\n- [x] Bulb response timeout\n- [ ] Change how background LEDs are treated\n- [ ] Merge [Effect] and `Duration` parameter\n- [x] Make Music workflow more usable\n- [ ] Handle groups of Bulbs\n### Testing\n- [ ] Cover all the main methods\n\n\n[1]: https://web.archive.org/web/20210131152550/https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf\n[2]: https://crates.io/crates/yeelight-cli\n\n## Troubleshooting\n\n### Connection Refused\n`Error: Os { code: 111, kind: ConnectionRefused, message: \"Connection refused\" }`\n- Make sure to turn off running VPNs.\n\n### Invalid Params\n`Error: ErrResponse(-5001, \"invalid params\")`\n- Turn off Music Flow on the Yeelight/Mi Home app.\n\n### Rate limit\n- Turn on [music mode](#music-mode)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleixb%2Fyeelight","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleixb%2Fyeelight","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleixb%2Fyeelight/lists"}