├── Milight.php ├── README.MD ├── composer.json └── example.php /Milight.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | class Milight 28 | { 29 | 30 | private $host; 31 | private $port; 32 | private $delay = 10000; //microseconds 33 | private $command_repeats = 10; 34 | private $rgbwActiveGroup = 0; // 0 means all 35 | private $whiteActiveGroup = 0; // 0 means all 36 | private $commandCodes = array( 37 | //RGBW Bulb commands 38 | 'rgbwAllOn' => array(0x42, 0x00), 39 | 'rgbwAllOff' => array(0x41, 0x00), 40 | 'rgbwGroup0Off' => array(0x41, 0x00), 41 | 'rgbwGroup0On' => array(0x42, 0x00), 42 | 'rgbwGroup1On' => array(0x45, 0x00), 43 | 'rgbwGroup2On' => array(0x47, 0x00), 44 | 'rgbwGroup3On' => array(0x49, 0x00), 45 | 'rgbwGroup4On' => array(0x4B, 0x00), 46 | 'rgbwGroup1Off' => array(0x46, 0x00), 47 | 'rgbwGroup2Off' => array(0x48, 0x00), 48 | 'rgbwGroup3Off' => array(0x4a, 0x00), 49 | 'rgbwGroup4Off' => array(0x4c, 0x00), 50 | 'rgbwAllNightMode' => array(0xC1, 0x00), 51 | 'rgbwGroup0NightMode' => array(0xC1, 0x00), 52 | 'rgbwGroup1NightMode' => array(0xC6, 0x00), 53 | 'rgbwGroup2NightMode' => array(0xC8, 0x00), 54 | 'rgbwGroup3NightMode' => array(0xCA, 0x00), 55 | 'rgbwGroup4NightMode' => array(0xCC, 0x00), 56 | 'rgbwBrightnessMax' => array(0x4e, 0x1b), 57 | 'rgbwBrightnessMin' => array(0x4e, 0x02), 58 | 'rgbwDiscoMode' => array(0x4d, 0x00), 59 | 'rgbwDiscoSlower' => array(0x43, 0x00), 60 | 'rgbwDiscoFaster' => array(0x44, 0x00), 61 | 'rgbwAllSetToWhite' => array(0xc2, 0x00), 62 | 'rgbwGroup0SetToWhite' => array(0xc2, 0x00), 63 | 'rgbwGroup1SetToWhite' => array(0xc5, 0x00), 64 | 'rgbwGroup2SetToWhite' => array(0xc7, 0x00), 65 | 'rgbwGroup3SetToWhite' => array(0xc9, 0x00), 66 | 'rgbwGroup4SetToWhite' => array(0xcb, 0x00), 67 | 'rgbwSetColorToViolet' => array(0x40, 0x00), 68 | 'rgbwSetColorToRoyalBlue' => array(0x40, 0x10), 69 | 'rgbwSetColorToBabyBlue' => array(0x40, 0x20), 70 | 'rgbwSetColorToAqua' => array(0x40, 0x30), 71 | 'rgbwSetColorToRoyalMint' => array(0x40, 0x40), 72 | 'rgbwSetColorToSeafoamGreen' => array(0x40, 0x50), 73 | 'rgbwSetColorToGreen' => array(0x40, 0x60), 74 | 'rgbwSetColorToLimeGreen' => array(0x40, 0x70), 75 | 'rgbwSetColorToYellow' => array(0x40, 0x80), 76 | 'rgbwSetColorToYellowOrange' => array(0x40, 0x90), 77 | 'rgbwSetColorToOrange' => array(0x40, 0xa0), 78 | 'rgbwSetColorToRed' => array(0x40, 0xb0), 79 | 'rgbwSetColorToPink' => array(0x40, 0xc0), 80 | 'rgbwSetColorToFusia' => array(0x40, 0xd0), 81 | 'rgbwSetColorToLilac' => array(0x40, 0xe0), 82 | 'rgbwSetColorToLavendar' => array(0x40, 0xf0), 83 | 84 | 85 | // White Bulb commands 86 | 'whiteAllOn' => array(0x35, 0x00), 87 | 'whiteAllOff' => array(0x39, 0x00), 88 | 'whiteGroup0On' => array(0x35, 0x00), 89 | 'whiteGroup0Off' => array(0x39, 0x00), 90 | 'whiteBrightnessUp' => array(0x3c, 0x00), 91 | 'whiteBrightnessDown' => array(0x34, 0x00), 92 | 'whiteGroup0BrightnessMax' => array(0xb5, 0x00), 93 | 'whiteGroup0NightMode' => array(0xbb, 0x00), 94 | 'whiteAllBrightnessMax' => array(0xb5, 0x00), 95 | 'whiteAllNightMode' => array(0xbb, 0x00), 96 | 'whiteWarmIncrease' => array(0x3e, 0x00), 97 | 'whiteCoolIncrease' => array(0x3f, 0x00), 98 | 'whiteGroup1On' => array(0x38, 0x00), 99 | 'whiteGroup1Off' => array(0x3b, 0x00), 100 | 'whiteGroup2On' => array(0x3d, 0x00), 101 | 'whiteGroup2Off' => array(0x33, 0x00), 102 | 'whiteGroup3On' => array(0x37, 0x00), 103 | 'whiteGroup3Off' => array(0x3a, 0x00), 104 | 'whiteGroup4On' => array(0x32, 0x00), 105 | 'whiteGroup4Off' => array(0x36, 0x00), 106 | 'whiteGroup1BrightnessMax' => array(0xb8, 0x00), 107 | 'whiteGroup2BrightnessMax' => array(0xbd, 0x00), 108 | 'whiteGroup3BrightnessMax' => array(0xb7, 0x00), 109 | 'whiteGroup4BrightnessMax' => array(0xb2, 0x00), 110 | 'whiteGroup1NightMode' => array(0xbb, 0x00), 111 | 'whiteGroup2NightMode' => array(0xb3, 0x00), 112 | 'whiteGroup3NightMode' => array(0xba, 0x00), 113 | 'whiteGroup4NightMode' => array(0xb6, 0x00), 114 | 115 | ); 116 | 117 | /** 118 | * @param int $delay 119 | */ 120 | public function setDelay($delay) 121 | { 122 | $this->delay = $delay; 123 | } 124 | 125 | /** 126 | * @return int 127 | */ 128 | public function getDelay() 129 | { 130 | return $this->delay; 131 | } 132 | 133 | public function setRepeats($repeats) { 134 | $this->command_repeats = $repeats; 135 | } 136 | 137 | private function setActiveGroup($Group) { 138 | if ($Group < 0 || $Group > 4) { 139 | throw new \Exception('Active group must be between 0 and 4. 0 means all groups'); 140 | } 141 | return $Group; 142 | } 143 | 144 | /** 145 | * @param int $rgbwActiveGroup 146 | * @throws Exception 147 | */ 148 | public function setRgbwActiveGroup($rgbwActiveGroup) { 149 | $this->rgbwActiveGroup = $this->setActiveGroup($rgbwActiveGroup); 150 | } 151 | 152 | // Same as setRgbwActiveGroup. Exists just to make method invocation easier according to the convention 153 | /** 154 | * @param int $rgbwActiveGroup 155 | * @throws Exception 156 | */ 157 | public function rgbwSetActiveGroup($rgbwActiveGroup) 158 | { 159 | $this->setRgbwActiveGroup($rgbwActiveGroup); 160 | } 161 | 162 | /** 163 | * @throws Exception 164 | * @return int 165 | */ 166 | public function getRgbwActiveGroup() 167 | { 168 | return $this->rgbwActiveGroup; 169 | } 170 | 171 | 172 | /** 173 | * @param int $whiteActiveGroup 174 | * @throws Exception 175 | */ 176 | public function setWhiteActiveGroup($whiteActiveGroup) { 177 | $this->whiteActiveGroup = $this->setActiveGroup($whiteActiveGroup); 178 | } 179 | 180 | // Same as setWhiteActiveGroup. Exists just to make method invocation easier according to the convention 181 | /** 182 | * @param int $whiteActiveGroup 183 | * @throws Exception 184 | */ 185 | public function whiteSetActiveGroup($whiteActiveGroup) 186 | { 187 | $this->setWhiteActiveGroup($whiteActiveGroup); 188 | } 189 | 190 | /** 191 | * @throws Exception 192 | * @return int 193 | */ 194 | public function getWhiteActiveGroup() 195 | { 196 | return $this->whiteActiveGroup; 197 | } 198 | 199 | public function __construct($host = '10.10.100.254', $port = 8899) 200 | { 201 | $this->host = $host; 202 | $this->port = $port; 203 | } 204 | 205 | 206 | public function sendCommand(Array $command) 207 | { 208 | $command[] = 0x55; // last byte is always 0x55, will be appended to all commands 209 | $message = vsprintf(str_repeat('%c', count($command)), $command); 210 | for($repetition=0; $repetition<$this->command_repeats; $repetition++) { 211 | if ($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) { 212 | socket_sendto($socket, $message, strlen($message), 0, $this->host, $this->port); 213 | socket_close($socket); 214 | usleep($this->getDelay()); //wait 100ms before sending next command 215 | } 216 | } 217 | } 218 | 219 | public function command($commandName) 220 | { 221 | $this->sendCommand($this->commandCodes[$commandName]); 222 | } 223 | 224 | public function rgbwSendOnToActiveGroup() { 225 | $this->rgbwSendOnToGroup($this->getRgbwActiveGroup()); 226 | } 227 | 228 | public function rgbwSendOnToGroup($group) { 229 | $activeGroupOnCommand = 'rgbwGroup' . $group . 'On'; 230 | $this->command($activeGroupOnCommand); 231 | } 232 | 233 | public function rgbwSendOffToGroup($group) { 234 | $activeGroupOffCommand = 'rgbwGroup' . $group . 'Off'; 235 | $this->command($activeGroupOffCommand); 236 | } 237 | 238 | public function rgbwSetGroupToWhite($group) { 239 | $activeCommand = 'rgbwGroup' . $group . 'SetToWhite'; 240 | $this->command($activeCommand); 241 | } 242 | 243 | public function rgbwSetGroupToNightMode($group) { 244 | $this->rgbwSendOffToGroup($group); 245 | $activeCommand = 'rgbwGroup' . $group . 'NightMode'; 246 | $this->command($activeCommand); 247 | } 248 | 249 | public function whiteSendOnToGroup($group) { 250 | $activeGroupOnCommand = 'whiteGroup' . $group . 'On'; 251 | $this->command($activeGroupOnCommand); 252 | } 253 | 254 | public function whiteSendOffToGroup($group) { 255 | $activeGroupOffCommand = 'whiteGroup' . $group . 'Off'; 256 | $this->command($activeGroupOffCommand); 257 | } 258 | 259 | public function whiteSetGroupToNightMode($group) { 260 | $activeCommand = 'whiteGroup' . $group . 'NightMode'; 261 | $this->command($activeCommand); 262 | } 263 | 264 | public function whiteSendOnToActiveGroup() { 265 | $this->whiteSendOnToGroup($this->getWhiteActiveGroup()); 266 | } 267 | 268 | public function rgbwAllOn() 269 | { 270 | $this->command('rgbwAllOn'); 271 | } 272 | 273 | public function rgbwAllOff() 274 | { 275 | $this->command('rgbwAllOff'); 276 | } 277 | 278 | public function rgbwGroup1On() 279 | { 280 | $this->command('rgbwGroup1On'); 281 | } 282 | 283 | public function rgbwGroup2On() 284 | { 285 | $this->command('rgbwGroup2On'); 286 | } 287 | 288 | public function rgbwGroup3On() 289 | { 290 | $this->command('rgbwGroup3On'); 291 | } 292 | 293 | public function rgbwGroup4On() 294 | { 295 | $this->command('rgbwGroup4On'); 296 | } 297 | 298 | public function rgbwGroup1Off() 299 | { 300 | $this->command('rgbwGroup1Off'); 301 | } 302 | 303 | public function rgbwGroup2Off() 304 | { 305 | $this->command('rgbwGroup2Off'); 306 | } 307 | 308 | public function rgbwGroup3Off() 309 | { 310 | $this->command('rgbwGroup3Off'); 311 | } 312 | 313 | public function rgbwGroup4Off() 314 | { 315 | $this->command('rgbwGroup4Off'); 316 | } 317 | 318 | public function rgbwAllNightMode() 319 | { 320 | $this->rgbwAlloff(); 321 | $this->command('rgbwAllNightMode'); 322 | } 323 | 324 | public function rgbwGroup1NightMode() 325 | { 326 | $this->rgbwGroup1off(); 327 | $this->command('rgbwGroup1NightMode'); 328 | } 329 | 330 | public function rgbwGroup2NightMode() 331 | { 332 | $this->rgbwGroup2off(); 333 | $this->command('rgbwGroup2NightMode'); 334 | } 335 | 336 | public function rgbwGroup3NightMode() 337 | { 338 | $this->rgbwGroup3off(); 339 | $this->command('rgbwGroup3NightMode'); 340 | } 341 | 342 | public function rgbwGroup4NightMode() 343 | { 344 | $this->rgbwGroup4off(); 345 | $this->command('rgbwGroup4NightMode'); 346 | } 347 | 348 | public function rgbwBrightnessMax() 349 | { 350 | $this->rgbwSendOnToActiveGroup(); 351 | $this->command('rgbwBrightnessMax'); 352 | } 353 | 354 | public function rgbwBrightnessMin() 355 | { 356 | $this->rgbwSendOnToActiveGroup(); 357 | $this->command('rgbwBrightnessMin'); 358 | } 359 | 360 | public function rgbwAllBrightnessMin() 361 | { 362 | $this->setRgbwActiveGroup(0); 363 | $this->rgbwSendOnToActiveGroup(); 364 | $this->command('rgbwBrightnessMin'); 365 | } 366 | 367 | public function rgbwAllBrightnessMax() 368 | { 369 | $this->setRgbwActiveGroup(0); 370 | $this->rgbwSendOnToActiveGroup(); 371 | $this->command('rgbwBrightnessMax'); 372 | } 373 | 374 | public function rgbwGroup1BrightnessMax() 375 | { 376 | $this->setRgbwActiveGroup(1); 377 | $this->rgbwSendOnToActiveGroup(); 378 | $this->command('rgbwBrightnessMax'); 379 | } 380 | 381 | public function rgbwGroup2BrightnessMax() 382 | { 383 | $this->setRgbwActiveGroup(2); 384 | $this->rgbwSendOnToActiveGroup(); 385 | $this->command('rgbwBrightnessMax'); 386 | } 387 | 388 | public function rgbwGroup3BrightnessMax() 389 | { 390 | $this->setRgbwActiveGroup(3); 391 | $this->rgbwSendOnToActiveGroup(); 392 | $this->command('rgbwBrightnessMax'); 393 | } 394 | 395 | public function rgbwGroup4BrightnessMax() 396 | { 397 | $this->setRgbwActiveGroup(4); 398 | $this->rgbwSendOnToActiveGroup(); 399 | $this->command('rgbwBrightnessMax'); 400 | } 401 | 402 | public function rgbwGroup1BrightnessMin() 403 | { 404 | $this->setRgbwActiveGroup(1); 405 | $this->rgbwSendOnToActiveGroup(); 406 | $this->command('rgbwBrightnessMin'); 407 | } 408 | 409 | public function rgbwGroup2BrightnessMin() 410 | { 411 | $this->setRgbwActiveGroup(2); 412 | $this->rgbwSendOnToActiveGroup(); 413 | $this->command('rgbwBrightnessMin'); 414 | } 415 | 416 | public function rgbwGroup3BrightnessMin() 417 | { 418 | $this->setRgbwActiveGroup(3); 419 | $this->rgbwSendOnToActiveGroup(); 420 | $this->command('rgbwBrightnessMin'); 421 | } 422 | 423 | public function rgbwGroup4BrightnessMin() 424 | { 425 | $this->setRgbwActiveGroup(4); 426 | $this->rgbwSendOnToActiveGroup(); 427 | $this->command('rgbwBrightnessMin'); 428 | } 429 | 430 | public function rgbwBrightnessPercent($brightnessPercent,$group=null) { 431 | if ($brightnessPercent < 0 || $brightnessPercent > 100) { 432 | throw new \Exception('Brightness percent must be between 0 and 100'); 433 | } 434 | $brightnessPercent = round(2+(($brightnessPercent/100)*25)); 435 | $group = isset($group) ? $group : $this->getRgbwActiveGroup(); 436 | $this->rgbwSendOnToGroup($group); 437 | $this->sendCommand(array(0x4e, $brightnessPercent)); 438 | } 439 | 440 | public function rgbwDiscoMode() 441 | { 442 | $this->rgbwSendOnToActiveGroup(); 443 | $this->command('rgbwDiscoMode'); 444 | } 445 | 446 | public function rgbwDiscoSlower() 447 | { 448 | $this->rgbwSendOnToActiveGroup(); 449 | $this->command('rgbwDiscoSlower'); 450 | } 451 | 452 | public function rgbwDiscoFaster() 453 | { 454 | $this->rgbwSendOnToActiveGroup(); 455 | $this->command('rgbwDiscoFaster'); 456 | } 457 | 458 | public function rgbwAllSetToWhite() 459 | { 460 | $this->command('rgbwAllSetToWhite'); 461 | } 462 | 463 | public function rgbwGroup1SetToWhite() 464 | { 465 | $this->command('rgbwGroup1SetToWhite'); 466 | } 467 | 468 | public function rgbwGroup2SetToWhite() 469 | { 470 | $this->command('rgbwGroup2SetToWhite'); 471 | } 472 | 473 | public function rgbwGroup3SetToWhite() 474 | { 475 | $this->command('rgbwGroup3SetToWhite'); 476 | } 477 | 478 | public function rgbwGroup4SetToWhite() 479 | { 480 | $this->command('rgbwGroup4SetToWhite'); 481 | } 482 | 483 | public function rgbwSetColorToViolet() 484 | { 485 | $this->rgbwSendOnToActiveGroup(); 486 | $this->command('rgbwSetColorToViolet'); 487 | } 488 | 489 | public function rgbwSetColorToRoyalBlue() 490 | { 491 | $this->rgbwSendOnToActiveGroup(); 492 | $this->command('rgbwSetColorToRoyalBlue'); 493 | } 494 | 495 | public function rgbwSetColorToBabyBlue() 496 | { 497 | $this->rgbwSendOnToActiveGroup(); 498 | $this->command('rgbwSetColorToBabyBlue'); 499 | } 500 | 501 | /** 502 | * Sets color of the currently active group to white. 503 | */ 504 | public function rgbwSetColorToWhite() 505 | { 506 | if ($this->getActiveGroup() == 0) { 507 | $this->rgbwAllSetToWhite(); 508 | return; 509 | } 510 | $this->command('rgbwGroup'.strval($this->getActiveGroup()).'SetToWhite'); 511 | } 512 | 513 | public function rgbwSetColorToAqua() 514 | { 515 | $this->rgbwSendOnToActiveGroup(); 516 | $this->command('rgbwSetColorToAqua'); 517 | } 518 | 519 | public function rgbwSetColorToRoyalMint() 520 | { 521 | $this->rgbwSendOnToActiveGroup(); 522 | $this->command('rgbwSetColorToRoyalMint'); 523 | } 524 | 525 | public function rgbwSetColorToSeafoamGreen() 526 | { 527 | $this->rgbwSendOnToActiveGroup(); 528 | $this->command('rgbwSetColorToSeafoamGreen'); 529 | } 530 | 531 | public function rgbwSetColorToGreen() 532 | { 533 | $this->rgbwSendOnToActiveGroup(); 534 | $this->command('rgbwSetColorToGreen'); 535 | } 536 | 537 | public function rgbwSetColorToLimeGreen() 538 | { 539 | $this->rgbwSendOnToActiveGroup(); 540 | $this->command('rgbwSetColorToLimeGreen'); 541 | } 542 | 543 | public function rgbwSetColorToYellow() 544 | { 545 | $this->rgbwSendOnToActiveGroup(); 546 | $this->command('rgbwSetColorToYellow'); 547 | } 548 | 549 | public function rgbwSetColorToYellowOrange() 550 | { 551 | $this->rgbwSendOnToActiveGroup(); 552 | $this->command('rgbwSetColorToYellowOrange'); 553 | } 554 | 555 | public function rgbwSetColorToOrange() 556 | { 557 | $this->rgbwSendOnToActiveGroup(); 558 | $this->command('rgbwSetColorToOrange'); 559 | } 560 | 561 | public function rgbwSetColorToRed() 562 | { 563 | $this->rgbwSendOnToActiveGroup(); 564 | $this->command('rgbwSetColorToRed'); 565 | } 566 | 567 | public function rgbwSetColorToPink() 568 | { 569 | $this->rgbwSendOnToActiveGroup(); 570 | $this->command('rgbwSetColorToPink'); 571 | } 572 | 573 | public function rgbwSetColorToFusia() 574 | { 575 | $this->rgbwSendOnToActiveGroup(); 576 | $this->command('rgbwSetColorToFusia'); 577 | } 578 | 579 | public function rgbwSetColorToLilac() 580 | { 581 | $this->rgbwSendOnToActiveGroup(); 582 | $this->command('rgbwSetColorToLilac'); 583 | } 584 | 585 | public function rgbwSetColorToLavendar() 586 | { 587 | $this->rgbwSendOnToActiveGroup(); 588 | $this->command('rgbwSetColorToLavendar'); 589 | } 590 | 591 | public function whiteAllOn() 592 | { 593 | $this->command('whiteAllOn'); 594 | } 595 | 596 | public function whiteAllOff() 597 | { 598 | $this->command('whiteAllOff'); 599 | } 600 | 601 | public function whiteBrightnessUp() 602 | { 603 | $this->whiteSendOnToActiveGroup(); 604 | $this->command('whiteBrightnessUp'); 605 | } 606 | 607 | public function whiteBrightnessDown() 608 | { 609 | $this->whiteSendOnToActiveGroup(); 610 | $this->command('whiteBrightnessDown'); 611 | } 612 | 613 | public function whiteAllBrightnessMax() 614 | { 615 | $this->command('whiteAllBrightnessMax'); 616 | } 617 | 618 | public function whiteAllBrightnessMin() 619 | { 620 | $this->setWhiteActiveGroup(0); 621 | $this->whiteSendOnToActiveGroup(); 622 | for ($i = 0; $i < 10; $i++) { 623 | $this->command('whiteBrightnessDown'); 624 | } 625 | 626 | } 627 | 628 | public function whiteAllNightMode() 629 | { 630 | $this->command('whiteAllNightMode'); 631 | } 632 | 633 | 634 | public function whiteWarmIncrease() 635 | { 636 | $this->whiteSendOnToActiveGroup(); 637 | $this->command('whiteWarmIncrease'); 638 | } 639 | 640 | public function whiteCoolIncrease() 641 | { 642 | $this->whiteSendOnToActiveGroup(); 643 | $this->command('whiteCoolIncrease'); 644 | } 645 | 646 | public function whiteGroup1On() 647 | { 648 | $this->command('whiteGroup1On'); 649 | } 650 | 651 | public function whiteGroup1Off() 652 | { 653 | $this->command('whiteGroup1Off'); 654 | } 655 | 656 | public function whiteGroup2On() 657 | { 658 | $this->command('whiteGroup2On'); 659 | } 660 | 661 | public function whiteGroup2Off() 662 | { 663 | $this->command('whiteGroup2Off'); 664 | } 665 | 666 | public function whiteGroup3On() 667 | { 668 | $this->command('whiteGroup3On'); 669 | } 670 | 671 | public function whiteGroup3Off() 672 | { 673 | $this->command('whiteGroup3Off'); 674 | } 675 | 676 | public function whiteGroup4On() 677 | { 678 | $this->command('whiteGroup4On'); 679 | } 680 | 681 | public function whiteGroup4Off() 682 | { 683 | $this->command('whiteGroup4Off'); 684 | } 685 | 686 | public function whiteGroup1BrightnessMax() 687 | { 688 | $this->command('whiteGroup1BrightnessMax'); 689 | } 690 | 691 | public function whiteGroup2BrightnessMax() 692 | { 693 | $this->command('whiteGroup2BrightnessMax'); 694 | } 695 | 696 | public function whiteGroup3BrightnessMax() 697 | { 698 | $this->command('whiteGroup3BrightnessMax'); 699 | } 700 | 701 | public function whiteGroup4BrightnessMax() 702 | { 703 | $this->command('whiteGroup4BrightnessMax'); 704 | } 705 | 706 | public function whiteGroup1BrightnessMin() 707 | { 708 | $this->setWhiteActiveGroup(1); 709 | $this->whiteSendOnToActiveGroup(); 710 | for ($i = 0; $i < 10; $i++) { 711 | $this->command('whiteBrightnessDown'); 712 | } 713 | } 714 | 715 | public function whiteGroup2BrightnessMin() 716 | { 717 | $this->setWhiteActiveGroup(2); 718 | $this->whiteSendOnToActiveGroup(); 719 | for ($i = 0; $i < 10; $i++) { 720 | $this->command('whiteBrightnessDown'); 721 | } 722 | } 723 | 724 | public function whiteGroup3BrightnessMin() 725 | { 726 | $this->setWhiteActiveGroup(3); 727 | $this->whiteSendOnToActiveGroup(); 728 | for ($i = 0; $i < 10; $i++) { 729 | $this->command('whiteBrightnessDown'); 730 | } 731 | } 732 | 733 | public function whiteGroup4BrightnessMin() 734 | { 735 | $this->setWhiteActiveGroup(4); 736 | $this->whiteSendOnToActiveGroup(); 737 | for ($i = 0; $i < 10; $i++) { 738 | $this->command('whiteBrightnessDown'); 739 | } 740 | } 741 | 742 | public function whiteGroup1NightMode() 743 | { 744 | $this->command('whiteGroup1NightMode'); 745 | } 746 | 747 | public function whiteGroup2NightMode() 748 | { 749 | $this->command('whiteGroup2NightMode'); 750 | } 751 | 752 | public function whiteGroup3NightMode() 753 | { 754 | $this->command('whiteGroup3NightMode'); 755 | } 756 | 757 | public function whiteGroup4NightMode() 758 | { 759 | $this->command('whiteGroup4NightMode'); 760 | } 761 | 762 | public function rgbwSetColorHsv(Array $hsvColor) 763 | { 764 | $milightColor = $this->hslToMilightColor($hsvColor); 765 | $activeGroupOnCommand = 'rgbwGroup' . $this->getRgbwActiveGroup() . 'On'; 766 | $this->command($activeGroupOnCommand); 767 | $this->sendCommand(array(0x40, $milightColor)); 768 | } 769 | 770 | 771 | public function rgbwSetColorHexString($color) 772 | { 773 | $rgb = $this->rgbHexToIntArray($color); 774 | $hsl = $this->rgbToHsl($rgb[0], $rgb[1], $rgb[2]); 775 | $milightColor = $this->hslToMilightColor($hsl); 776 | $this->rgbwSendOnToActiveGroup(); 777 | $this->sendCommand(array(0x40, $milightColor)); 778 | } 779 | 780 | 781 | public function rgbHexToIntArray($hexColor) 782 | { 783 | $hexColor = ltrim($hexColor, '#'); 784 | 785 | $hexColorLenghth = strlen($hexColor); 786 | if ($hexColorLenghth != 8 && $hexColorLenghth != 6) { 787 | throw new \Exception('Color hex code must match 8 or 6 characters'); 788 | } 789 | if ($hexColorLenghth == 8) { 790 | $r = hexdec(substr($hexColor, 2, 2)); 791 | $g = hexdec(substr($hexColor, 4, 2)); 792 | $b = hexdec(substr($hexColor, 6, 2)); 793 | if (($r == 0 && $g == 0 && $b == 0) || ($r == 255 && $g == 255 && $b == 255)) { 794 | throw new \Exception('Color cannot be black or white'); 795 | } 796 | return array($r, $g, $b); 797 | } 798 | 799 | $r = hexdec(substr($hexColor, 0, 2)); 800 | $g = hexdec(substr($hexColor, 2, 2)); 801 | $b = hexdec(substr($hexColor, 4, 2)); 802 | if (($r == 0 && $g == 0 && $b == 0) || ($r == 255 && $g == 255 && $b == 255)) { 803 | throw new \Exception('Color cannot be black or white'); 804 | } 805 | return array($r, $g, $b); 806 | } 807 | 808 | 809 | public function rgbToHsl($r, $g, $b) 810 | { 811 | $r = $r / 255; 812 | $g = $g / 255; 813 | $b = $b / 255; 814 | $max = max($r, $g, $b); 815 | $min = min($r, $g, $b); 816 | $l = ($max + $min) / 2; 817 | $d = $max - $min; 818 | $h = ''; 819 | 820 | if ($d == 0) { 821 | $h = $s = 0; 822 | } else { 823 | $s = $d / (1 - abs(2 * $l - 1)); 824 | 825 | switch ($max) { 826 | case $r: 827 | $h = 60 * fmod((($g - $b) / $d), 6); 828 | if ($b > $g) { 829 | $h += 360; 830 | } 831 | break; 832 | 833 | case $g: 834 | $h = 60 * (($b - $r) / $d + 2); 835 | break; 836 | 837 | case $b: 838 | $h = 60 * (($r - $g) / $d + 4); 839 | break; 840 | } 841 | } 842 | return array($h, $s, $l); 843 | } 844 | 845 | public function hslToMilightColor($hsl) 846 | { 847 | $color = (256 + 176 - (int)($hsl[0] / 360.0 * 255.0)) % 256; 848 | return $color + 0xfa; 849 | } 850 | 851 | } 852 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | Milight/LimitlessLED/EasyBulb Complete PHP API 2 | ============== 3 | 4 | The complete API of Milight/LimitlessLED/EasyBulb written in PHP. 5 | This code has been tested on Wifi Bridge V.4 and is working pretty well. 6 | Any help and bugfixes are welcome. 7 | 8 | 9 | Note (1): There are two different channels for white and RGBW on Wifi Bridge so you can't mix white bulbs with RGBW bulbs on the same group. 10 | 11 | Note (2): Brightness (dimming) values for RGBW bulbs are different for white and RGB modes and brightness value is saved in bulbs separately either mode. 12 | 13 | Note (3): RGBW bulbs can't mix RGB and white colors, these bulbs only can operate in white or RGB mode so you can't set saturation. Only brightness can be set in RGB mode. 14 | 15 | Note (4): Since Wifi Bridge V.4 the web interface for Wifi Bridge configuration has been removed and static IP can be set only from mobile app or using AT commands (currently we are working on adding PHP API for configuration and auto bridge discovery) 16 | 17 | ~~Note (4): Web interface is back in new firmware update. You can update the firmware and use web-based interface (by typing IP in browser) to set static IP address.~~ 18 | 19 | ~~here's the link to the firmware update file: (the file has been removed from the server!)~~ 20 | 21 | ~~[http://www.limitlessled.com/download/LIMITLESSLED_FIRMWARE_UPGRADE_V4_BRIDGE_27Nov2014.bin](http://www.limitlessled.com/download/LIMITLESSLED_FIRMWARE_UPGRADE_V4_BRIDGE_27Nov2014.bin)~~ 22 | 23 | ~~Warning: I have updated my Wifi bridge V.4 successfully to this firmware version, but you use this update on your own responsibility. Recently I've noticed, the update is breaking some incompatible Wifi bridges.~~ 24 | 25 | There are two methods for setting active group one for RGBW bulbs (setRgbwActiveGroup or rgbwSetActiveGroup) and for white bulbs (setWhiteActiveGroup or whiteSetActiveGroup). After setting active channel you will be able to send commands to chosen bulb group. 26 | 27 | Bulbs only support 256 colors (not 16 millions) but there is a method for setting RGB hex strings (for example, #FF1254). This is then configured to nearest supported color. It is also possible to provide HSV colors. 28 | 29 | Example: 30 | 31 | ```php 32 | rgbwAllOn(); 38 | $milight->rgbwAllSetToWhite(); 39 | $milight->rgbwAllBrightnessMax(); 40 | sleep(2); 41 | $milight->setRgbwActiveGroup(1); 42 | $milight->rgbwBrightnessPercent(50); 43 | sleep(2); 44 | $milight->setRgbwActiveGroup(2); 45 | $milight->rgbwSetColorHexString('FF1254'); // or #FF1254 46 | $milight->rgbwBrightnessPercent(90); 47 | sleep(2); 48 | $milight->whiteAllOn(); 49 | $milight->whiteAllBrightnessMax(); 50 | sleep(2); 51 | $milight->whiteGroup1NightMode(); 52 | sleep(2); 53 | $milight->setWhiteActiveGroup(2); 54 | $milight->whiteWarmIncrease(); 55 | $milight->whiteWarmIncrease(); 56 | $milight->whiteWarmIncrease(); 57 | ``` 58 | 59 | Have fun! 60 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yasharrashedi/limitless-led", 3 | "description": "LimitlessLED/Milight integration library", 4 | "minimum-stability": "stable", 5 | "require": {}, 6 | "autoload": { 7 | "files": ["Milight.php"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | rgbwAllOn(); 10 | $milight->rgbwAllSetToWhite(); 11 | $milight->rgbwAllBrightnessMax(); 12 | sleep(2); 13 | $milight->setRgbwActiveGroup(1); 14 | $milight->rgbwBrightnessPercent(50); 15 | sleep(2); 16 | $milight->setRgbwActiveGroup(2); 17 | $milight->rgbwSetColorHexString('FF1254'); // or #FF1254 18 | $milight->rgbwBrightnessPercent(90); 19 | sleep(2); 20 | $milight->whiteAllOn(); 21 | $milight->whiteAllBrightnessMax(); 22 | sleep(2); 23 | $milight->whiteGroup1NightMode(); 24 | sleep(2); 25 | $milight->setWhiteActiveGroup(2); 26 | $milight->whiteWarmIncrease(); 27 | $milight->whiteWarmIncrease(); 28 | $milight->whiteWarmIncrease(); --------------------------------------------------------------------------------