function _drawDevicesList() {
		_stopDevicesRefresh();
		if ( $( "#" + _prefix + "-known-devices" ).length === 0 ) {
			return;
		}
		_indexFeatures = {}; _indexDevices = {};
		$.when( _getDevicesInfosAsync() )
			.done( function( devicesInfos ) {
				if ( devicesInfos.devices.length > 0 ) {
					$.each( devicesInfos.devices, function( i, device ) {
						var room = api.getRoomObject( device.mainRoomId );
						device.roomName = room ? room.name : 'unknown';
					});
					// Sort the devices by room / name
					devicesInfos.devices.sort( function( a, b ) {
						if ( a.protocol === b.protocol ) {
							var x = a.roomName.toLowerCase(), y = b.roomName.toLowerCase();
							return x < y ? -1 : x > y ? 1 : 0;
						}
						return a.protocol < b.protocol ? -1 : a.protocol > b.protocol ? 1 : 0;
					});
					
					var html =	'<table><tr>'
						+			'<th>' + Utils.getLangString( _prefix + "_room" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_address" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_endpoint" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_signal_quality" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_last_update" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_feature" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_device" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_association" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_action" ) + '</th>'
						+		'</tr>';
					$.each( devicesInfos.devices, function( i, device ) {
						var rowSpan = ( device.features.length > 1 ? ' rowspan="' + device.features.length + '"' : '' );
						html += '<tr>'
							+		'<td class="' + _prefix + '-room-name"' + rowSpan + '>' + device.roomName + '</td>'
							+		'<td class="' + _prefix + '-address"' + rowSpan + '>' + device.address + '</td>'
							+		'<td' + rowSpan + '>' + device.endPoint + '</td>'
							+		'<td' + rowSpan + '>' + ( device.quality >= 0 ? device.quality : '' ) + '</td>'
							+		'<td' + rowSpan + '>' + _convertTimestampToLocaleString( device.lastUpdate ) + '</td>';
						var isFirstRow = true;

						device.features.sort( function( a, b ) {
							if ( a.deviceName < b.deviceName ) {
								return -1;
							} else if ( a.deviceName > b.deviceName ) {
								return 1;
							}
							return 0;
						});

						var countDevices = {};
						$.each( device.features, function( i, feature ) {
							countDevices[ feature.deviceId.toString() ] = countDevices[ feature.deviceId.toString() ]  != null ? countDevices[ feature.deviceId.toString() ] + 1 : 1;
						});

						var lastDeviceId = -1;
						var deviceRowSpan = '1';
						$.each( device.features, function( i, feature ) {
							var productId = device.address + ';' + device.endPoint;
							_indexFeatures[ productId + ';' + feature.name ] = feature;
							_indexDevices[ feature.deviceId.toString() ] = device.protocol;
							if ( !feature.settings ) {
								feature.settings = {};
							}
							/*feature.settings = {};
							$.each( ( api.getDeviceStateVariable( feature.deviceId, PLUGIN_CHILD_SID, "Setting", { dynamic: false } ) || "" ).split( "," ), function( i, settingName ) {
								feature.settings[ settingName ] = true;
							} );*/
							if ( !isFirstRow ) {
								html += '<tr>';
							}
							html +=	'<td>'
								+		'<div class="' + _prefix + '-feature-name">' + feature.name + '</div>'
								+		( feature.data ? '<div class="' + _prefix + '-feature-data">' + feature.data + '</div>' : '' )
								+	'</td>';

							if ( feature.deviceId != lastDeviceId ) {
								lastDeviceId = feature.deviceId;
								deviceRowSpan = ' rowspan="' + countDevices[ feature.deviceId.toString() ] + '"';
								html +=	'<td' + deviceRowSpan +'>'
									//+			'<div class="' + _prefix + '-device-type">'
									+		'<div><span class="' + _prefix + '-device-name">' + feature.deviceName + '</span> (#' + feature.deviceId + ')</div>'
									+		'<div>'
									+				Utils.getLangString( feature.deviceTypeName )
									+				( device.isNew ? ' <span style="color:red">NEW</span>' : '' )
									+				( feature.settings.pulse ? ' PULSE' : '' )
									+				( feature.settings.toggle ? ' TOGGLE' : '' )
									+		'</div>'
									//+		'</div>'
									+	'</td>'
									+	'<td' + deviceRowSpan +'>'
									+		_getAssociationHtml( "device", feature.association.devices, 0 )
									//+		_getAssociationHtml( "device", feature.association.devices, 1 )
									+		_getAssociationHtml( "scene", feature.association.scenes, 0 )
									//+		_getAssociationHtml( "scene", feature.association.scenes, 1 )
									+		_getAssociationHtml( "ziblue-device", feature.association.ziGateDevices, 0 )
									+	'</td' + deviceRowSpan +'>'
									+	'<td' + deviceRowSpan +' align="center">'
									//+		( !device.isNew && ( feature.settings.button || feature.settings.receiver ) ?
									+		( !device.isNew ?
												'<i class="' + _prefix + '-actions fa fa-caret-down fa-lg" aria-hidden="true" data-product-id="' + productId + '" data-feature-name="' + feature.name + '"></i>'
												: '' )
									+	'</td>';
							}
							html +=	'</tr>';
							isFirstRow = false;
						} );
					});
					html += '</table>';
					$("#" + _prefix + "-known-devices").html( html );
				} else {
					$("#" + _prefix + "-known-devices").html( Utils.getLangString( _prefix + "_no_device" ) );
				}
				_devicesLastRefresh = Date.now();
				_resumeDevicesRefresh();
			} );
	}
/**
	 * Draw and manage external device list
	 */
Draw and manage external device list
Draw and manage external device list
function _drawDevicesList() {
		_stopDevicesRefresh();
		if ( $( "#" + _prefix + "-known-devices" ).length === 0 ) {
			return;
		}
		_indexFeatures = {}; _indexDevices = {};
		$.when( _getDevicesInfosAsync() )
			.done( function( devicesInfos ) {
				if ( devicesInfos.devices.length > 0 ) {
					$.each( devicesInfos.devices, function( i, device ) {
						var room = api.getRoomObject( device.mainRoomId );
						device.roomName = room ? room.name : 'unknown';
					});
					devicesInfos.devices.sort( function( a, b ) {
						if ( a.protocol === b.protocol ) {
							var x = a.roomName.toLowerCase(), y = b.roomName.toLowerCase();
							return x < y ? -1 : x > y ? 1 : 0;
						}
						return a.protocol < b.protocol ? -1 : a.protocol > b.protocol ? 1 : 0;
					});
					var html =	'<table><tr>'
						+			'<th>' + Utils.getLangString( _prefix + "_room" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_address" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_endpoint" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_signal_quality" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_last_update" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_feature" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_device" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_association" ) + '</th>'
						+			'<th>' + Utils.getLangString( _prefix + "_action" ) + '</th>'
						+		'</tr>';
					$.each( devicesInfos.devices, function( i, device ) {
						var rowSpan = ( device.features.length > 1 ? ' rowspan="' + device.features.length + '"' : '' );
						html += '<tr>'
							+		'<td class="' + _prefix + '-room-name"' + rowSpan + '>' + device.roomName + '</td>'
							+		'<td class="' + _prefix + '-address"' + rowSpan + '>' + device.address + '</td>'
							+		'<td' + rowSpan + '>' + device.endPoint + '</td>'
							+		'<td' + rowSpan + '>' + ( device.quality >= 0 ? device.quality : '' ) + '</td>'
							+		'<td' + rowSpan + '>' + _convertTimestampToLocaleString( device.lastUpdate ) + '</td>';
						var isFirstRow = true;
						device.features.sort( function( a, b ) {
							if ( a.deviceName < b.deviceName ) {
								return -1;
							} else if ( a.deviceName > b.deviceName ) {
								return 1;
							}
							return 0;
						});
						var countDevices = {};
						$.each( device.features, function( i, feature ) {
							countDevices[ feature.deviceId.toString() ] = countDevices[ feature.deviceId.toString() ]  != null ? countDevices[ feature.deviceId.toString() ] + 1 : 1;
						});
						var lastDeviceId = -1;
						var deviceRowSpan = '1';
						$.each( device.features, function( i, feature ) {
							var productId = device.address + ';' + device.endPoint;
							_indexFeatures[ productId + ';' + feature.name ] = feature;
							_indexDevices[ feature.deviceId.toString() ] = device.protocol;
							if ( !feature.settings ) {
								feature.settings = {};
							}
							if ( !isFirstRow ) {
								html += '<tr>';
							}
							html +=	'<td>'
								+		'<div class="' + _prefix + '-feature-name">' + feature.name + '</div>'
								+		( feature.data ? '<div class="' + _prefix + '-feature-data">' + feature.data + '</div>' : '' )
								+	'</td>';
							if ( feature.deviceId != lastDeviceId ) {
								lastDeviceId = feature.deviceId;
								deviceRowSpan = ' rowspan="' + countDevices[ feature.deviceId.toString() ] + '"';
								html +=	'<td' + deviceRowSpan +'>'
									+		'<div><span class="' + _prefix + '-device-name">' + feature.deviceName + '</span> (#' + feature.deviceId + ')</div>'
									+		'<div>'
									+				Utils.getLangString( feature.deviceTypeName )
									+				( device.isNew ? ' <span style="color:red">NEW</span>' : '' )
									+				( feature.settings.pulse ? ' PULSE' : '' )
									+				( feature.settings.toggle ? ' TOGGLE' : '' )
									+		'</div>'
									+	'</td>'
									+	'<td' + deviceRowSpan +'>'
									+		_getAssociationHtml( "device", feature.association.devices, 0 )
									+		_getAssociationHtml( "scene", feature.association.scenes, 0 )
									+		_getAssociationHtml( "ziblue-device", feature.association.ziGateDevices, 0 )
									+	'</td' + deviceRowSpan +'>'
									+	'<td' + deviceRowSpan +' align="center">'
									+		( !device.isNew ?
												'<i class="' + _prefix + '-actions fa fa-caret-down fa-lg" aria-hidden="true" data-product-id="' + productId + '" data-feature-name="' + feature.name + '"></i>'
												: '' )
									+	'</td>';
							}
							html +=	'</tr>';
							isFirstRow = false;
						} );
					});
					html += '</table>';
					$("#" + _prefix + "-known-devices").html( html );
				} else {
					$("#" + _prefix + "-known-devices").html( Utils.getLangString( _prefix + "_no_device" ) );
				}
				_devicesLastRefresh = Date.now();
				_resumeDevicesRefresh();
			} );
	}
function _drawDevicesList ( ) { _stopDevicesRefresh ( ) ; if ( $ ( "#" + _prefix + "-known-devices" ) . length === 0 ) { return ; } _indexFeatures = { } ; _indexDevices = { } ; $ . when ( _getDevicesInfosAsync ( ) ) . done ( function ( devicesInfos ) { if ( devicesInfos . devices . length > 0 ) { $ . each ( devicesInfos . devices , function ( i , device ) { var room = api . getRoomObject ( device . mainRoomId ) ; device . roomName = room ? room . name : 'unknown' ; } ) ; devicesInfos . devices . sort ( function ( a , b ) { if ( a . protocol === b . protocol ) { var x = a . roomName . toLowerCase ( ) , y = b . roomName . toLowerCase ( ) ; return x < y ? - 1 : x > y ? 1 : 0 ; } return a . protocol < b . protocol ? - 1 : a . protocol > b . protocol ? 1 : 0 ; } ) ; var html = '<table><tr>' + '<th>' + Utils . getLangString ( _prefix + "_room" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_address" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_endpoint" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_signal_quality" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_last_update" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_feature" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_device" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_association" ) + '</th>' + '<th>' + Utils . getLangString ( _prefix + "_action" ) + '</th>' + '</tr>' ; $ . each ( devicesInfos . devices , function ( i , device ) { var rowSpan = ( device . features . length > 1 ? ' rowspan="' + device . features . length + '"' : '' ) ; html += '<tr>' + '<td class="' + _prefix + '-room-name"' + rowSpan + '>' + device . roomName + '</td>' + '<td class="' + _prefix + '-address"' + rowSpan + '>' + device . address + '</td>' + '<td' + rowSpan + '>' + device . endPoint + '</td>' + '<td' + rowSpan + '>' + ( device . quality >= 0 ? device . quality : '' ) + '</td>' + '<td' + rowSpan + '>' + _convertTimestampToLocaleString ( device . lastUpdate ) + '</td>' ; var isFirstRow = true ; device . features . sort ( function ( a , b ) { if ( a . deviceName < b . deviceName ) { return - 1 ; } else if ( a . deviceName > b . deviceName ) { return 1 ; } return 0 ; } ) ; var countDevices = { } ; $ . each ( device . features , function ( i , feature ) { countDevices [ feature . deviceId . toString ( ) ] = countDevices [ feature . deviceId . toString ( ) ] != null ? countDevices [ feature . deviceId . toString ( ) ] + 1 : 1 ; } ) ; var lastDeviceId = - 1 ; var deviceRowSpan = '1' ; $ . each ( device . features , function ( i , feature ) { var productId = device . address + ';' + device . endPoint ; _indexFeatures [ productId + ';' + feature . name ] = feature ; _indexDevices [ feature . deviceId . toString ( ) ] = device . protocol ; if ( ! feature . settings ) { feature . settings = { } ; } if ( ! isFirstRow ) { html += '<tr>' ; } html += '<td>' + '<div class="' + _prefix + '-feature-name">' + feature . name + '</div>' + ( feature . data ? '<div class="' + _prefix + '-feature-data">' + feature . data + '</div>' : '' ) + '</td>' ; if ( feature . deviceId != lastDeviceId ) { lastDeviceId = feature . deviceId ; deviceRowSpan = ' rowspan="' + countDevices [ feature . deviceId . toString ( ) ] + '"' ; html += '<td' + deviceRowSpan + '>' + '<div><span class="' + _prefix + '-device-name">' + feature . deviceName + '</span> (#' + feature . deviceId + ')</div>' + '<div>' + Utils . getLangString ( feature . deviceTypeName ) + ( device . isNew ? ' <span style="color:red">NEW</span>' : '' ) + ( feature . settings . pulse ? ' PULSE' : '' ) + ( feature . settings . toggle ? ' TOGGLE' : '' ) + '</div>' + '</td>' + '<td' + deviceRowSpan + '>' + _getAssociationHtml ( "device" , feature . association . devices , 0 ) + _getAssociationHtml ( "scene" , feature . association . scenes , 0 ) + _getAssociationHtml ( "ziblue-device" , feature . association . ziGateDevices , 0 ) + '</td' + deviceRowSpan + '>' + '<td' + deviceRowSpan + ' align="center">' + ( ! device . isNew ? '<i class="' + _prefix + '-actions fa fa-caret-down fa-lg" aria-hidden="true" data-product-id="' + productId + '" data-feature-name="' + feature . name + '"></i>' : '' ) + '</td>' ; } html += '</tr>' ; isFirstRow = false ; } ) ; } ) ; html += '</table>' ; $ ( "#" + _prefix + "-known-devices" ) . html ( html ) ; } else { $ ( "#" + _prefix + "-known-devices" ) . html ( Utils . getLangString ( _prefix + "_no_device" ) ) ; } _devicesLastRefresh = Date . now ( ) ; _resumeDevicesRefresh ( ) ; } ) ; }
Draw and manage external device list
Draw and manage external device list
// Sort the devices by room / name /*feature.settings = {};
							$.each( ( api.getDeviceStateVariable( feature.deviceId, PLUGIN_CHILD_SID, "Setting", { dynamic: false } ) || "" ).split( "," ), function( i, settingName ) {
								feature.settings[ settingName ] = true;
							} );*/ //+			'<div class="' + _prefix + '-device-type">' //+		'</div>' //+		_getAssociationHtml( "device", feature.association.devices, 1 ) //+		_getAssociationHtml( "scene", feature.association.scenes, 1 ) //+		( !device.isNew && ( feature.settings.button || feature.settings.receiver ) ?