API Yeelight довольно подробно описан, и, в принципе, все управление сводится к поиску лампочек через широковещательные пакеты UDP и обмену JSON строками между лампочкой и сервером. Ниже я выкладываю свой гуглоперевод этого API. За основу взял класс Yeelight отсюда: https://github.com/elberth90/yeelight-api-client , и немного упростил его.
Итак, что же нужно чтобы управлять лампочкой (светильником, RGB-лентой) Yeelight:
1. Поставить на смартфон фирменное приложение Yeelight и в настройках включить режим разработчика.
2. Распаковать из прикрепленного архива библиотеку классов Yeelight_library.php в папку .../htdocs/modules/Yeelight/.
3. Создать сценарий поиска лампочек и формирования класса, объектов и методов для Majordomo, назовем его, например, searchYeelightBulb с нижеследующим кодом.
Код: Выделить всё
//Скрипт для MD, поиск устройств в сети, создание объектов MD, создание и заполнение свойств объектов MD
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
//Создание класса MD Yeelight, классовых свойств и методов
addClass('Yeelight');
addClassProperty('Yeelight', 'id', 0); //Создаёт свойство класса и указывает, что необходимо хранить историю значений 0 дней
addClassProperty('Yeelight', 'model', 0);
addClassProperty('Yeelight', 'status', 0);
addClassProperty('Yeelight', 'model', 0);
addClassProperty('Yeelight', 'bright', 0);
addClassProperty('Yeelight', 'Location', 0);
addClassProperty('Yeelight', 'name', 0);
addClassProperty('Yeelight', 'support', 0);
addClassMethod('Yeelight', 'on_off');
addClassMethod('Yeelight', 'set_bright');
addClassMethod('Yeelight', 'set_name');
//=======================================
//Создание объектов класса
// Поиск устройств
$client = new YeelightClient();
$bulbList_prop = $client->search_prop();
foreach ($bulbList_prop as $bulb) {
//получаем из массива bulbList_prop характеристики устройств
$id = trim($bulb[id]);
$Location = trim($bulb[Location]);
$model = trim($bulb[model]);
$name = trim($bulb[name]);
$COLOR_MODE = trim($bulb[color_mode]);
$powerTXT = $bulb[power];
if ($powerTXT == "on") { $power = 1; }
if ($powerTXT = "off") { $power = 0; }
$bright = trim($bulb[bright]);
$ct = trim($bulb[ct]);
$rgb = dechex($bulb[rgb]);
$hue = trim($bulb[hue]);
$sat = trim($bulb[sat]);
$support = trim($bulb[support]);
//получаем список объектов класса
$objects=getObjectsByClass("Yeelight");
$searhID = 0;
foreach($objects as $obj) {
if ((gg($obj['TITLE'].".id")) == $id){
$searhID += 1;
}
}
if ($searhID) {
echo "Устройство с id".$id." в базе MD уже есть"."<br />";
} else {
echo "Устройство с ID".$id." в базе MD не найдено. Добавляем новый объект"."<br />";
if ($name) {
$objName = $name;
} else {
$objName = "Bulb_".$id;
}
addClassObject('Yeelight', $objName); //создаем объект с новым id
//заполняем классовые свойства объекта
setGlobal($objName.".id",$id);
setGlobal($objName.".model",$model);
setGlobal($objName.".status",$power);
setGlobal($objName.".bright",$bright);
setGlobal($objName.".Location",$Location);
setGlobal($objName.".name",$name);
setGlobal($objName.".support",$support);
//создаем свойства объекта с учетом специфики ламп
if ($model =="stripe" OR $model =="color") {
echo "Лампа цветная - создаем свойства и методы управления цветом"."<br />";
$result = strpos ($support, 'set_rgb');
if ($result) {
setGlobal($objName.".rgb",$rgb);
addClassMethod('Yeelight', 'set_rgb');
echo "Cоздается свойство RGB"."<br />";
}
$result = strpos ($support, 'set_ct_abx');
if ($result) {
setGlobal($objName.".ct",$ct);
addClassMethod('Yeelight', 'set_ct');
echo "Cоздается свойство CT"."<br />";
}
$result = strpos ($support, 'set_hsv');
if ($result) {
setGlobal($objName.".hue",$hue);
setGlobal($objName.".sat",$sat);
addClassMethod('Yeelight', 'set_hsv');
echo "Cоздается свойство HSV"."<br />";
}
} elseif ($model =="mono") {
echo "Лампа монохромная - базовые свойства созданы"."<br />";
}
}
}
4. Также сценарий создает пустые методы, которые надо будет заполнить кодом из нижеследующего списка согласно имени метода:
Код: Выделить всё
//========= метод on_off (включение/выключение) ===================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$status = $this->getProperty('status');
if ($status) {$power = 'on'; }
if (!$status) {$power = 'off'; }
$data = [
"Location" => $Location,
"id" => $id,
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setPower($power, 'smooth', 1000); //включить/выключить
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
//========= метод set_bright (установка яркости) ====================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$bright = (int) ($this->getProperty('bright'));
$data = [
"Location" => $Location,
"id" => $id,
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setBright($bright, 'smooth', 1000); //установить яркость
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
//=======метод set_rgb (установка цвета RGB)======================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$rgb = hexdec($this->getProperty('rgb'));
$data = [
"Location" => "$Location",
"id" => "$id",
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setRgb($rgb, 'smooth', 1000); //установить цвет
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
//=======метод set_ct (установка цвета CT)=======================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$ct = (int) ($this->getProperty('ct'));
$data = [
"Location" => "$Location",
"id" => "$id",
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setCtAbx($ct, 'smooth', 1000); //установить цвет
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
//=======метод set_hsv (установка цвета Hsv)======================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$hue = (int) ($this->getProperty('hue'));
$sat = (int) ($this->getProperty('sat'));
$data = [
"Location" => "$Location",
"id" => "$id",
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setHsv($hue, $sat, 'smooth', 1000); //установить цвет
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
//=======метод set_name(установка имени)=======================
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$Location = $this->getProperty('Location');
$id = $this->getProperty('id');
$name = $this->getProperty('name');
$data = [
"Location" => "$Location",
"id" => "$id",
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->setName($name); //установить имя
if (array_key_exists('result', $res)) {
$result = $res [result][0];
//переменная содержит ответ от лампочки
}
if (array_key_exists('error', $res)) {
$result = $res [error][message].". Code ".$res [error][code];
DebMes("Ошибка Yeelight: ".$result);
}
5. Здесь у нас возникает вопрос: привязывать ли методы к изменению свойств? Думаю однозначно можно привязать метод set_name(установка имени устройства) к свойству name. Привязка остальных зависит от вашего желания иметь обратную связь.
6. По поводу обратной связи... Конечно лампочка подтверждает исполнение команды и мы это отслеживаем в методах.
Но полноценной обратной связи в данной реализации управления нет, т.е. если мы включим лампочку из приложения Yeelight со смартфона, статус ее в Majordomo не изменится. Что же делать?
Вариант первый - обратная связь не нужна, мы управляем лампочкой только через Majordomo. Привязываем исполнение всех методов к изменению соответствующих свойств и не паримся больше по этому поводу.
Вариант второй - можно периодически проверять состояние лампочек отдельным сценарием и обновлять свойства. Частоту запуска сценария выбираем исходя из компромисса между временем отображения изменений и нагрузкой сети.
Код сценария:
Код: Выделить всё
include_once(DIR_MODULES.'Yeelight/Yeelight_library.php');
$objects=getObjectsByClass("Yeelight");
foreach($objects as $obj) {
$objName = $obj['TITLE'];
$id = gg($objName.".id");
$Location = gg($objName.".Location");
$data = [
"Location" => $Location,
"id" => $id,
];
$socketFactory = new Factory();
$bulbFactory = new BulbFactory($socketFactory);
$bulb = $bulbFactory->create($data);
$res = $bulb->getProp([BulbProperties::POWER,BulbProperties::BRIGHT,BulbProperties::RGB,BulbProperties::COLOR_TEMPERATURE,BulbProperties::HUE,BulbProperties::SATURATION]);
$powerTXT = $res[result][0];
if ($powerTXT == "on") { $power = 1; }
if ($powerTXT = "off") { $power = 0; }
setGlobal($objName.".status",$power);
$bright = $res[result][1];
setGlobal($objName.".bright",$bright);
$rgb = dechex($res[result][2]);
if ($rgb) {setGlobal($objName.".rgb",$rgb); }
$ct = $res[result][3];
if ($ct) {setGlobal($objName.".ct",$ct); }
$hue = $res[result][4];
if ($hue) {setGlobal($objName.".hue",$hue); }
$sat = $res[result][5];
if ($sat) {setGlobal($objName.".sat",$sat); }
echo ". ";
}
echo "ok";
В последних двух вариантах привязку методов к свойствам не делаем, так как при работе скрипта обновления получим повторную отработку методов.
7. Далее создаем пункты меню с контролами для управления. Здесь все типовое, единственно следует иметь ввиду, что если методы у нас не привязаны к свойствам, при настройке контрола указываем и свойство и метод. И аналогично при использовании в своих сценариях устанавливаем свойство и запускаем метод. А если привязаны - управляем только изменением свойств.
P.S. Код я протестировал пока только на белой лампочке. Скоро придет цветная - протестирую и на ней.