{"id":18342061,"url":"https://github.com/vikstrous/zengge-lightcontrol","last_synced_at":"2025-09-05T10:47:21.969Z","repository":{"id":36214976,"uuid":"40519255","full_name":"vikstrous/zengge-lightcontrol","owner":"vikstrous","description":"A command line tool and library to control Zengge lightbulbs","archived":false,"fork":false,"pushed_at":"2020-05-09T21:59:32.000Z","size":161,"stargazers_count":104,"open_issues_count":15,"forks_count":23,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-07T12:03:42.189Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vikstrous.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-11T03:27:34.000Z","updated_at":"2024-09-16T20:15:17.000Z","dependencies_parsed_at":"2022-07-29T21:09:43.218Z","dependency_job_id":null,"html_url":"https://github.com/vikstrous/zengge-lightcontrol","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vikstrous/zengge-lightcontrol","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vikstrous%2Fzengge-lightcontrol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vikstrous%2Fzengge-lightcontrol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vikstrous%2Fzengge-lightcontrol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vikstrous%2Fzengge-lightcontrol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vikstrous","download_url":"https://codeload.github.com/vikstrous/zengge-lightcontrol/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vikstrous%2Fzengge-lightcontrol/sbom","scorecard":{"id":921603,"data":{"date":"2025-08-11","repo":{"name":"github.com/vikstrous/zengge-lightcontrol","commit":"3565a82ffa9c2f89441c340a6479a430da4d1b09"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/5 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-25T03:53:07.026Z","repository_id":36214976,"created_at":"2025-08-25T03:53:07.027Z","updated_at":"2025-08-25T03:53:07.027Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273747795,"owners_count":25160651,"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-09-05T02:00:09.113Z","response_time":402,"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":[],"created_at":"2024-11-05T20:29:24.103Z","updated_at":"2025-09-05T10:47:21.669Z","avatar_url":"https://github.com/vikstrous.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zengge LightControl\n\nZengge have a line of cheap WiFi enabled lightbulbs made in China. They don't have consistent branding, but some of the names I've seen them use in their products and apps are \"magichue\", \"magic home\", \"LED magic color\" and \"ledmagical\". They can be bought from Alibaba in bulk for anywhere between $1 and $18 depending on quantity. There are also resellers in other places under other brand names like \"Flux\" and \"Leegoal\".\n\nHere's where they come from: [Alibaba](http://zengge.en.alibaba.com/product/1959075082-213407227/)\n\nThe bulbs use a simple binary protocol. The tools in this repository will help you use it to control the bulb over WiFi. There are also tools for controlling it over the Internet.\n\nThis command line tool and library uses what they call the \"2014 protocol\". The lightbulb module ID I tested with is HF-LPB100-ZJ200.\n\n## Example usage\n\n```\ngo get github.com/vikstrous/zengge-lightcontrol/cmd/zengge-lightcontrol\nzengge-lightcontrol local --host 1.2.3.4:5577 set-power off\n```\n\n## Hardware\n\nThe main chip used is HF-LPB100. You can find out everything about it [here](http://www.hi-flying.com/products_detail/\u0026productId=68f4fd7b-39f8-4995-93ab-53193ac5cf22.html). It's a simple WiFi access point and/or client. It runs FreeRTOS. The manufacturer provides a development board and SDK for writing applications for it.\n\n## Software\n\nThe bulb is built using the chip manufacturer's SDK from what I could tell. It has a web server on it, but the management web UI is removed. All that's left is a server serving a basic auth prompt and then a 404 error.\n\nZengge has an Android and iOS app called \"magic home\". It has the ability to interact with both the router and the lightbulb ports (more on that later). It also has the ability to register a lightbulb with their cloud control server and control it even when not on the same LAN.\n\n## Protocols\n\nThe bulbs have 3 ports open: TCP 80, TCP 5577 and UDP 48899. They also have the ability to make outbound connections and receive commands from a server on the Internet. Commands sent that way can control only the bulb, not the router.\n\nThe TCP port is used to control the lightbulb and the UDP port is used to control the WiFi router on it. I will be referring to the former as the bulb port and the latter as the router port. This is a very cheap embedded device, so it doesn't do any fancy cryptography or authentication. It accepts simple commands on those ports.\n\n### HTTP server\n\nFirst of all, if you want to authenticate with the HTTP server, the username/password are admin/nimda. All I see is 404 errors when I try to open it in Firefox, so not very interesting. Chrome doesn't even think it's HTTP and curl hangs, so it's not the nicest web server.\n\n### Router Port\n\nThe router port is documented in the manual pdf [version 1.9](http://www.hi-flying.com/downloadsfront.do?method=picker\u0026flag=all\u0026id=dc406e44-84ec-4be1-ab11-a4ce403f6d3f\u0026fileId=0f147d14-d0aa-4fc8-b01f-36e43418d19d), is also available.\n\nIt's running firmware version 1.0.06.\n\nThe UDP port is 48899. There is a bit of a trick to making it work. There is a \"wifi configuration password\" set. You have to send \"HF-A11ASSISTHREAD\" followed by \"+ok\" before you begin to interact with it / send other commands. It's a simple ASCII over UDP protocol. I think every message has to fit in one UDP frame, but I haven't confirmed that.\n\nMany of the commands in the manual don't show up when you run AT+H, so the manual is essential. For example, `AT+SMEM` is not documented. For me it returns `12488[max_blk_size], 14692[total_size]`.\n\nThere are `AT+` commands listed in `AT+H` that differ compared to the documentation or are undocumented:\n\n    AT+NDBGL:set/get debug level - not documented; two values - x,y; y is 0 or 1; x is int, \u003e= 0\n    AT+SLPEN: Put on/off the GPIO7. - ??? this is the Sleep_RQ pin\n    AT+UPAUTO: Start the remote upgrade by config file. - invalid command error\n    AT+UPCFG: Start the remote upgrade default setting. - invalid command error\n    AT+UPWEB: Start the remote upgrade webpages. - invalid command error\n    AT+WEBSWITCH: Set/Get the parameters of WEB page. - invalid command error\n    AT+WEBVER: Get WEB version. - returns None\n\nIt seems like the device is left in its default \"Transparent Transmission Mode\", which means that it can receive management commands over the network instead of only over a serial port.\n\nThe module ID returned by the router is `HF-LPB100-ZJ200`\nThe detailed version info is `10 Cyrus.xu_Sam (2015/04/10)`\nThe wifi driver is 141440 bytes.\n\nRemote control works over \"HTTP protocol transfer\"\nThe `AT+HTTPURL` command shows that the bulb connects to `http://wifi.magichue.net:8805`\n\nIts user agent is `lwip1.3.2`\n\nThere is a strange set of commands that allow the bulb to send HTTP requests on your behalf, acting like a primitive proxy.\n\nI found out that the router can be used in station and access point mode at the same time. This means that it's ideal for re-use as a low power simple man-in-the-middle proxy.\n\n### Bulb Port\n\nThere are 3 modes set with `AT+TMODE`:\n\n* Throughput mode - issue commands to lightbulb\n* Command mode - ???\n* PWM mode - manually adjust levels of GPIO pins\n\n#### GPIO commands (PWM mode)\n\nThese are documented in the router documentation linked to above. I have not tried actually using them.\n\nThe router has to be set to `pwm` mode using `AT+TMODE` for these to work.\n\nSome of the commands are:\n\n```\nGPIO \u003cchannel\u003e OUT \u003cvalue\u003e\nGPIO \u003cchannel\u003e GET\nPWM \u003cchannel\u003e \u003cfrequency\u003e \u003cduty\u003e\nPWM \u003cchannel\u003e GET\nPWM \u003cchannel\u003e SET\n```\n\n* channel can be 11,12,15,18,20,23\n* value can be 1 or 0 where 1 is high voltage and 0 is low voltage\n* frequency can be 500 to 60000\n* duty can be 0 to 100\n\nThere are also many hex commands:\n\n```\n0a - read all GPIO channels\n  -\u003e 8a\u003cvalue\u003e\n03\u003cchannel\u003e - toggle channel value\n  -\u003e 83\u003cchannel\u003e\u003cvalue\u003e\n30 - read all PWM channel frequencies\n  -\u003e b0\u003cfour two-byte values for channels 0-3\u003e\n32\u003cchannel\u003e\u003ctwo byte value\u003e - write PWM channel frequency\n  -\u003e b2\u003cchannel\u003e\u003ctwo byte value\u003e\n20 - read all pwm channel duty\n  -\u003e a0 \u003cfour bytes for channels 0-3\u003e\n24... - write all PWM channel duty\n  -\u003e a4...\n22... - write PWM channel duty\n  -\u003e a2...\n71 - save present GPIO,PWM settings\n  -\u003e fa\n04 - assert all GPIO channels low\n  -\u003e 8400\n05 - assert all GPIO channels high\n  -\u003e 85 01\n7e - read resources of module\n  -\u003e fe\u003coutput pin\u003e\u003cinput pin\u003e\u003cpwm pin\u003e\n```\n\n#### Bulb commands (throughput mode)\n\nThis protocol is less well documented. It's a binary protocol. All examples I'll be showing are in hex. I think my code is better documentation than this README can provide.\n\nAll commnads are of fixed length. The last byte is always a checksum.  The checksum is just the sum of all the previous bytes in the current command.\n\nThe following examples can give you an idea of how the protocol works. The rest can be seen re-implemented in protocol.go.\n\nThis example command **changes the color**:\n\n```\n31RRGGBBWWXXCC\n```\n\nwhere:\n\n* 31 is the ID of the command\n* RR is red\n* GG is green\n* BB is blue\n* WW is white\n* XX is whether to use the white value or not\n* CC is the checksum\n\nBooleans such as XX are represented as 0xf0 for True and 0x0f for False.\nThere is no response.\n\nThis command queries the **state of the bulb**:\n\n```\n818a8b96\n```\n\nThe result looks like this:\n\n```\n814423612101fefb8a000400f0e2\n```\n\nIt includes the following information:\n\n```go\ntype State struct {\n\tDeviceType    uint8\n\tIsOn          bool\n\tLedVersionNum uint8\n\tMode          uint8\n\tSlowness      uint8\n\tColor         Color\n}\n```\n\n### Cloud Control\n\nThis is called \"remote\" in the Android app. It allows the bulb to be controlled over the Internet.\n\nThe connection is established this way:\n\n1. The phone finds the mac address of the bulb\n1. The phone \"logs in\" to the cloud server using its device id and gets a cookie\n1. The phone registers the bulb by telling the server its mac address. This associates the bulb with the device id / user\n1. The phone uses AT+ commands to tell the bulb to connect to the cloud server\n1. The bulb makes a connection and tells the server its mac address\n\nCommands are sent to the bulb like this:\n\n1. The phone logs into the cloud server with its device id and gets a cookie\n1. The phone can now send commands to the bulb using the bulb binary protocol tunneled over HTTP to the server and over TCP from the server to the bulb\n\nDevice ids are uuid4 converted into numbers on android and in uuid format on iOS. In practice they can be any unique string.\n\nAll requests to the cloud server from the phone use \"authentication\" which consists of a simple AES256 encryption with a shared secret distributed with the application.\n\nEvery api call is sent to `http://wifi.magichue.net/WebMagicHome/ZenggeCloud/ZJ002.ashx` (yes, unencrypted). The body of the request is url encoded with content type `application/x-www-form-urlencoded`. The command to execute is in a header called `zg-app-cmd`.\n\nExample login request:\n\n```\nPOST /WebMagicHome/ZenggeCloud/ZJ002.ashx HTTP/1.1\nContent-Type: application/x-www-form-urlencoded;charset=UTF-8\nAccept-Charset: UTF-8\nzg-app-cmd: Login\nHost: wifi.magichue.net\nAccept-Encoding: gzip\nContent-Length: 439\n\nAppKey=65ee4e302f844df87939cbe879041a7ba2d0df17\u0026DevID=\u003cdevice id redacted\u003e\u0026AppVer=1.0.9\u0026CheckCode=c2+50+c9+6e+5f+76+f3+b2+1a+76+a1+c7+25+9d+d8+cc+53+b0+e6+ff+45+49+15+f6+72+30+28+c4+d9+f7+f6+29+e8+3e+04+3b+40+12+b5+12+75+eb+a7+3b+57+e6+ee+e9+af+54+79+d5+ac+af+b2+ca+7d+8d+ea+3d+1a+eb+c7+6f+31+0a+a6+db+55+e3+d8+f6+b2+27+74+c3+f3+65+f5+8d+2c+b6+d5+b3+6e+f4+ac+8f+bf+44+58+90+a8+3c+83+99+\u0026AppSys=Android\u0026Timestamp=Sat+Aug+08+17%3A34%3A01+PDT+2015\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvikstrous%2Fzengge-lightcontrol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvikstrous%2Fzengge-lightcontrol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvikstrous%2Fzengge-lightcontrol/lists"}