Skip to content

Commit

Permalink
v.1.0-beta
Browse files Browse the repository at this point in the history
* Добавлено автоопределение типа (модели) устройств во время поиска при условии, что устройство сообщает свой токен.
* Для шлюза Mi Smart Home Gateway 2 добавлен функционал работы с zigbee суб-устройствами (вкладка Zigbee):
  * получение списка суб-устройств;
  * удаление (отвязывание) суб-устройств;
  * перевод шлюза в режим сопряжения для добавления нового суб-устройства.
* В перечень устройств внесена камера Mi Dafang Smart Camera 120.
  • Loading branch information
skysilver-lab committed Jan 9, 2018
1 parent e7dfc57 commit 229eec9
Show file tree
Hide file tree
Showing 22 changed files with 234 additions and 15 deletions.
34 changes: 31 additions & 3 deletions modules/xiaomimiio/miio_devices_edit.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/*
* @author <[email protected]>
* @copyright 2017 Agaphonov Dmitri aka skysilver <[email protected]> (c)
* @version 0.9b
* @version 1.0b
*/

if ($this->owner->name == 'panel') {
Expand All @@ -14,7 +14,7 @@
$rec = SQLSelectOne("SELECT * FROM $table_name WHERE ID='$id'");

if ($this->mode == 'update') {

$this->getConfig();
$ok = 1;

Expand Down Expand Up @@ -86,6 +86,34 @@
$this->requestInfo($rec['ID']);
// а также, если определен тип устройства, то запросим текущие параметры (статус).
if ((int)$update_period == 0 && $rec['DEVICE_TYPE'] != '') $this->requestStatus($rec['ID']);
// Если тип устройства не указан, то пробуем получить тип устройства из miIO.info
if ($rec['DEVICE_TYPE'] == '') {
if ($this->config['API_LOG_DEBMES']) DebMes('Try to get device model from miIO.info for the device ' . $rec['IP'], 'xiaomimiio');

$this->getConfig();

if ($miio_module->config['API_IP']) $bind_ip = $miio_module->config['API_IP'];
else $bind_ip = '0.0.0.0';
if ($miio_module->config['API_LOG_MIIO']) $miio_debug = true;
else $miio_debug = false;

if (!class_exists('miIO', false)) {
include_once(DIR_MODULES . 'xiaomimiio/lib/miio.class.php');
}
$midev = new miIO($rec['IP'], $bind_ip, $rec['TOKEN'], $miio_debug);
if ($midev->getInfo(time())) {
if ($midev->data != '') {
$info = json_decode($midev->data, true);
$dev_type = $info['result']['model'];
if ($this->config['API_LOG_DEBMES']) DebMes($rec['IP'] . ' is ' . $dev_type, 'xiaomimiio');
if ($dev_type != '') {
$rec['DEVICE_TYPE'] = $dev_type;
SQLUpdate($table_name, $rec);
$this->requestStatus($rec['ID']);
}
}
}
}
}
}
} else {
Expand All @@ -94,7 +122,7 @@
}

if ($this->tab == 'data') {

$new_id = 0;
global $delete_id;

Expand Down
48 changes: 39 additions & 9 deletions modules/xiaomimiio/xiaomimiio.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @package project
* @author <[email protected]>
* @copyright 2017 Agaphonov Dmitri aka skysilver <[email protected]> (c)
* @version 0.9.5b
* @version 1.0b
*/

define ('MIIO_YEELIGHT_WHITE_BULB_PROPS', 'power,bright');
Expand Down Expand Up @@ -313,16 +313,16 @@ function discover($ip = '') {
include_once(DIR_MODULES . 'xiaomimiio/lib/miio.class.php');
}

$dev = new miIO(null, $bind_ip, null, $miio_debug);
$midev = new miIO(null, $bind_ip, null, $miio_debug);

// Выполняем broadcast-поиск устройств в локальной сети
if ($this->config['API_LOG_DEBMES']) DebMes("Run miIO-discover command", 'xiaomimiio');
$res = $dev->discover();
$res = $midev->discover();
if ($this->config['API_LOG_DEBMES']) DebMes("End miIO-discover command", 'xiaomimiio');

if ($res) {
// Обрабатываем результат поиска
$reply = $dev->data;
$reply = $midev->data;

if ($reply != '') {
if ($this->config['API_LOG_DEBMES']) DebMes("Reply = $reply", 'xiaomimiio');
Expand Down Expand Up @@ -353,7 +353,7 @@ function discover($ip = '') {

if ($this->config['API_LOG_DEBMES']) DebMes("Update the ip address and the token for the device $ip", 'xiaomimiio');
SQLUpdate('miio_devices', $dev_rec);

// Ответившее устройство выкинем из претендентов на оффлайн
for ($i = 0; $i < $count_devices; $i++) {
if ($dev_rec['ID'] == $all_devices[$i]['ID']) {
Expand All @@ -364,7 +364,7 @@ function discover($ip = '') {

$this->processCommand($dev_rec['ID'], 'online', 1);
} else {
// Если устройство нет в БД, то добавим его и установим свойство online
// Если устройство нет в БД, то добавим его
$dev_rec = array();
$dev_rec['IP'] = $ip;
if ($token != '') $dev_rec['TOKEN'] = $token;
Expand All @@ -373,7 +373,36 @@ function discover($ip = '') {
$dev_rec['DEVICE_TYPE_CODE'] = $device_type_code;
$dev_rec['TITLE'] = 'New ' . $dev_rec['DEVICE_TYPE_CODE'];
if ($this->config['API_LOG_DEBMES']) DebMes("Add new device with $ip", 'xiaomimiio');

// Если есть токен, то пробуем получить тип устройства из miIO.info
if ($dev_rec['TOKEN']) {
if ($this->config['API_LOG_DEBMES']) DebMes('Try to get device model from miIO.info for the device ' . $dev_rec['IP'], 'xiaomimiio');
$midev->data = '';
$midev->ip = $dev_rec['IP'];
$midev->token = $dev_rec['TOKEN'];
if ($midev->getInfo(time())) {
if ($midev->data != '') {
$info = json_decode($midev->data, true);
$dev_type = $info['result']['model'];
if ($this->config['API_LOG_DEBMES']) DebMes($dev_rec['IP'] . ' is ' . $dev_type, 'xiaomimiio');
if ($dev_type != '') $dev_rec['DEVICE_TYPE'] = $dev_type;
}
}
}

$dev_rec['ID'] = SQLInsert('miio_devices', $dev_rec);

if ($dev_rec['DEVICE_TYPE'] != '') {
$this->requestStatus($dev_rec['ID']);
if ($dev_rec['DEVICE_TYPE'] == 'lumi.gateway.v3') {
$this->processCommand($dev_rec['ID'], 'add_program', '');
$this->processCommand($dev_rec['ID'], 'del_program', '');
}
if ($dev_rec['DEVICE_TYPE'] == 'chuangmi.ir.v2') {
$this->processCommand($dev_rec['ID'], 'ir_play', '');
}
}

$this->processCommand($dev_rec['ID'], 'online', 1);
}
}
Expand Down Expand Up @@ -631,7 +660,7 @@ function search_miio_devices(&$out) {
*/

function edit_miio_devices(&$out, $id) {

require(DIR_MODULES.$this->name . '/miio_devices_edit.inc.php');

}
Expand Down Expand Up @@ -925,10 +954,11 @@ function processMessage($message, $command, $device_id) {
}
} elseif ($device['ID']) {

$res_commands[] = array('command' => 'message', 'value' => $message);
$res_commands[] = array('command' => 'online', 'value' => 1);

$res_commands[] = array('command' => 'command', 'value' => '');
$res_commands[] = array('command' => 'message', 'value' => $message);


if ($device['DEVICE_TYPE'] == 'lumi.gateway.v3') {
if ($command == 'get_prop_fm' && is_array($data['result'])) {
foreach($data['result'] as $key => $value) {
Expand Down
12 changes: 10 additions & 2 deletions templates/xiaomimiio/action_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h4 class="modal-title">Xiaomi miIO</h4>
<div class="modal-body">
<div class="float-right">
<img src="../templates/xiaomimiio/milogo.png" width="48" height="48">
<br><br><p><b>v.0.9.5b</b></p>
<br><br><p><b>v.1.0b</b></p>
</div>
<p class="float-left">
Модуль поддержки Wi-Fi устройств из экосистемы Xiaomi Mihome, взаимодействующих по протоколу miIO. <br><br>
Expand Down Expand Up @@ -130,19 +130,27 @@ <h6>Благодарности: <b>webms</b>, <b>srvsrvsrv</b>, <b>SergeJey</b>,
<li[#if TAB="gwradio"#] class="active"[#endif#]>
<a href="?data_source=<#DATA_SOURCE#>&view_mode=<#VIEW_MODE#>&id=<#ID#>&tab=gwradio">Радио</a>
</li>
<li[#if TAB="gwzigbee"#] class="active"[#endif#]>
<a href="?data_source=<#DATA_SOURCE#>&view_mode=<#VIEW_MODE#>&id=<#ID#>&tab=gwzigbee">Zigbee</a>
</li>
[#endif DEVICE_TYPE#]
</ul>
&nbsp;<br/><br/>
[#endif ID#]
[#if TAB=""#]
&nbsp;<br/><br/>
[#inc miio_devices_edit_default.html#]
[#endif TAB#]
[#if TAB="data"#]
&nbsp;<br/><br/>
[#inc miio_devices_edit_data.html#]
[#endif TAB#]
[#if TAB="gwradio"#]
&nbsp;<br/><br/>
[#inc miio_devices_edit_gwradio.html#]
[#endif TAB#]
[#if TAB="gwzigbee"#]
[#inc miio_devices_edit_gwzigbee.html#]
[#endif TAB#]
[#endif VIEW_MODE#]
<!-- / table miio_devices edit -->
<!-- table miio_devices view -->
Expand Down
Binary file added templates/xiaomimiio/img/milogo2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/mizigbee.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/86sw2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/ctrl_neutral2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/cube.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/isa.camera.df3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/magnet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/motion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/plug.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/sensor_ht.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/switch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/weather.v1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added templates/xiaomimiio/img/small/zigbee_unknown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions templates/xiaomimiio/miio_devices_edit_default.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<option value="zimi.powerstrip.v2" [#if DEVICE_TYPE="zimi.powerstrip.v2"#] selected[#endif#]>Mi Smart Power Strip 6 Plugs</option>
<option value="chuangmi.plug.m1" [#if DEVICE_TYPE="chuangmi.plug.m1"#] selected[#endif#]>Mi Smart Socket Plug 2</option>
<option value="isa.camera.isc5" [#if DEVICE_TYPE="isa.camera.isc5"#] selected[#endif#]>Mi Square Smart Camera</option>
<option value="isa.camera.df3" [#if DEVICE_TYPE="isa.camera.df3"#] selected[#endif#]>Mi Dafang Smart Camera 120</option>
<option value="rockrobo.vacuum.v1" [#if DEVICE_TYPE="rockrobo.vacuum.v1"#] selected[#endif#]>Mi Vacuum Cleaner</option>
<option value="philips.light.ceiling" [#if DEVICE_TYPE="philips.light.ceiling"#] selected[#endif#]>Philips EyeCare Smart Ceiling Lamp</option>
<option value="philips.light.sread1" [#if DEVICE_TYPE="philips.light.sread1"#] selected[#endif#]>Philips EyeCare Smart Desk Lamp 2</option>
Expand Down
152 changes: 152 additions & 0 deletions templates/xiaomimiio/miio_devices_edit_gwzigbee.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<br/>
<div>
<img src="../templates/xiaomimiio/img/milogo2.png" width="30" height="30">
&nbsp;&nbsp;&nbsp;
<a class="btn btn-primary" onclick="getZigbeeDevices('[#IP#]','[#TOKEN#]');"><i class="glyphicon glyphicon-refresh icon-white"></i>&nbsp;&nbsp;Обновить</a>
&nbsp;&nbsp;&nbsp;
<a class="btn btn-success" onclick="pairNewZigbee();"><i class="glyphicon glyphicon-link icon-white"></i>&nbsp;&nbsp;Привязать</a>
&nbsp;&nbsp;&nbsp;
<i id="gw_upd_zigbee_log"></i>&nbsp;&nbsp;&nbsp;<span id="gw_upd_zigbee_timer"></span>
</div>
<br/>
<fieldset>
<div id="gw_upd_zigbee_alert"></div>
<div style="width:700px">
<table class="table table-striped table-hover table-bordered" id="gw_upd_zigbee_table" align="left"></table>
</div>
</fieldset>
<div>
<a href="?data_source=<#DATA_SOURCE#>" class="btn btn-default"><#LANG_STRING_BACK#></a>
</div>

<script type="text/javascript">

//Получим список суб-девайсов при открытии вкладки "Zigbee"
getZigbeeDevices('[#IP#]','[#TOKEN#]');

const types = {
1: 'switch',
2: 'motion',
3: 'magnet',
7: 'ctrl_neutral2',
8: 'cube',
9: 'ctrl_neutral1',
10: 'sensor_ht',
11: 'plug',
12: '86sw2',
19: 'weather.v1',
20: 'ctrl_ln1',
21: 'ctrl_ln2',
52: 'sensor_motion.aq2',
53: 'sensor_magnet.aq2',
55: 'sensor_wleak.aq1',
1001: 'sensor_switch.aq2',
1002: '86sw1',
1003: 'smoke',
1004: 'natgas',
1005: '86plug'
};

function getZigbeeDevices(ip,token){
$("#gw_upd_zigbee_table").html('');
$("#gw_upd_zigbee_alert").html('');
var url="/ajax/xiaomimiio.html?op=test_api_cmd&dip="+ip+"&dtoken="+token+"&dcmd=get_device_prop&dopt=[\"lumi.0\",\"device_list\"]";
$.ajax({
url: url,
cache: false,
success: function(html){
//$("#gw_upd_zigbee_alert").html(html);
//$("#gw_upd_zigbee_alert").html('<pre class="pre-scrollable" id="gw_upd_zigbee_alert" style="word-wrap: break-word;">'+html+'</pre>');
var zdev = tryParseJSON(html);
if (zdev !== false) {
var zdev_count = zdev.result.length;
if (zdev_count > 0) {
let indx = 1;
for(let i=0; i<zdev_count; i+=5) {
var id = zdev.result[i];
if(id.indexOf('lumi.') === 0) id = id.substring(5);
var type = zdev.result[i+1];
var online = zdev.result[i+2];
if(id === '0') continue;
if(online == 1) {
online = '<span class="label label-success" title="Устройство в сети">Online</span>';
unpair = '<i id="'+id+'" onclick="unpairZigbee($(this).attr(\'id\'));" class="btn btn-default" title="Отвязать устройство от шлюза"><i class="glyphicon glyphicon-resize-full"></i></i>';
} else {
online = '<span class="label label-warning" title="Устройство не доступно">Offline</span>';
unpair = '<i id="'+id+'" onclick="unpairZigbee($(this).attr(\'id\'));" class="btn btn-default" title="Отвязать устройство от шлюза"><i class="glyphicon glyphicon-resize-full"></i></i>';
}
if (types[type]) {
model = types[type];
img_td = '<td style="vertical-align:middle;width:60px" class="text-center"><img src="../templates/xiaomimiio/img/small/'+model+'.png" height="40px" onError="this.src=\'../templates/xiaomimiio/img/small/zigbee_unknown.png\'"></td>';
} else {
model = 'unknown';
img_td = '<td style="vertical-align:middle;width:60px" class="text-center"><img src="../templates/xiaomimiio/img/small/zigbee_unknown.png" height="40px"></td>';
}
$('#gw_upd_zigbee_table').append('<tr><td style="vertical-align:middle;width:50px" class="text-center">'+(indx)+'</td>'+img_td+'<td style="vertical-align:middle;min-width:170px" class="text-center">'+id+'</td><td style="vertical-align:middle;width:50px" class="text-center">'+type+'</td><td style="vertical-align:middle" class="text-center">'+model+'</td><td style="vertical-align:middle;width:90px" class="text-center">'+online+'</td><td style="vertical-align:middle;width:70px" class="text-center">'+unpair+'</td></tr>');
indx+=1;
}
} else {
$("#gw_upd_zigbee_alert").html('<div class="alert alert-warning" role="alert" id="gw_upd_zigbee_alert">Zigbee-устройств не обнаружено.</div>');
}
} else {
$("#gw_upd_zigbee_alert").html('<div class="alert alert-warning" role="alert" id="gw_upd_zigbee_alert">Проблема с получением данных от шлюза.</div>');
}
}
});
}

function pairNewZigbee(){
var url="/ajax/xiaomimiio.html?op=test_api_cmd&dip=[#IP#]&dtoken=[#TOKEN#]&dcmd=start_zigbee_join&dopt=[30]";
$("#gw_upd_zigbee_log").html('');
$('#gw_upd_zigbee_log').html('Перевод шлюза в режим сопряжения');
$.ajax({
url: url,
cache: false,
success: function(html){
$("#gw_upd_zigbee_log").html(html);
$('#gw_upd_zigbee_log').html('Шлюз в режиме сопряжения');
$('#gw_upd_zigbee_timer').html('30');
setTimeout(pairTimer, 1000);
}
});

}

function unpairZigbee(sid){
var yesno = confirm("Вы действительно хотите отвязать устройство "+sid+" от шлюза?");
if (yesno) {
var url="/ajax/xiaomimiio.html?op=test_api_cmd&dip=[#IP#]&dtoken=[#TOKEN#]&dcmd=remove_device&dopt=[\""+sid+"\"]";
$("#gw_upd_zigbee_alert").html(url);
$.ajax({
url: url,
cache: false,
success: function(html){
$("#gw_upd_zigbee_alert").html('<pre class="pre-scrollable" id="gw_upd_zigbee_alert" style="word-wrap: break-word;">'+html+'</pre>');
}
});
}
}

function pairTimer(){
var obj = document.getElementById('gw_upd_zigbee_timer');
obj.innerHTML--;
if (obj.innerHTML == 0){
$('#gw_upd_zigbee_log').html('Сеанс сопряжения завершен');
$('#gw_upd_zigbee_timer').html('');
getZigbeeDevices('[#IP#]','[#TOKEN#]');
setTimeout(function(){}, 1000);
} else {
setTimeout(pairTimer, 1000);
}
}


function tryParseJSON (jsonString){
try {
var o = JSON.parse(jsonString);
if (o && typeof o === "object") return o;
}
catch (e) { }
return false;
};
</script>
2 changes: 1 addition & 1 deletion templates/xiaomimiio/miio_devices_search_admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
</td>
<td style="vertical-align:middle">
[#if DEVICE_TYPE!=""#]
<img src="../templates/xiaomimiio/img/small/[#DEVICE_TYPE#].png" height="40px">
<img src="../templates/xiaomimiio/img/small/[#DEVICE_TYPE#].png" height="40px" onError="this.src='../templates/xiaomimiio/img/small/unknown.png'">
[#else#]
<img src="../templates/xiaomimiio/img/small/unknown.png" height="36px">
[#endif#]
Expand Down

0 comments on commit 229eec9

Please sign in to comment.