UNPKG

iobroker.rflink

Version:
898 lines (817 loc) 37.5 kB
<html> <link rel="stylesheet" type="text/css" href="../../lib/css/themes/jquery-ui/redmond/jquery-ui.min.css"/> <link rel="stylesheet" type="text/css" href="../../lib/css/jqGrid/ui.jqgrid-4.5.4.css"/> <link rel="stylesheet" type="text/css" href="../../lib/css/jquery.multiselect-1.13.css"/> <script type="text/javascript" src="../../lib/js/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="../../socket.io/socket.io.js"></script> <script type="text/javascript" src="../../lib/js/jquery-ui-1.10.3.full.min.js"></script> <script type="text/javascript" src="../../lib/js/jqGrid/jquery.jqGrid-4.5.4.min.js"></script> <script type="text/javascript" src="../../lib/js/jqGrid/grid.locale-all.js"></script> <link rel="stylesheet" type="text/css" href="../../css/adapter.css"/> <script type="text/javascript" src="../../js/translate.js"></script> <script type="text/javascript" src="../../js/adapter-settings.js"></script> <script type="text/javascript" src="parse.js"></script> <script type="text/javascript" src="words.js"></script> <style> .oneWidth { width: 120px; } .pair-on { background: rgb(255, 153, 153) !important; } .no-address { color: rgb(255, 15, 15); font-weight: bold; } .auto-pair-problem { color: mediumvioletred; font-weight: bold; } #devices tr:nth-child(even) { background: lightgray; } @keyframes highlight { 0% { color: #00f900 } 80% { color: green } 100% { color: black; } } .highlight { animation: highlight 2s; } @keyframes show-pair-off { 0% { color: #F90000 } 80% { color: red } 100% { color: black; } } .show-pair-off { animation: show-pair-off 2s; } #drop-zone { width: calc(100% - 10px); height: calc(100% - 10px); position: absolute; opacity: 0.8; top: 0; left: 0; background: #eee; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; z-index: 1; font-size: 32px; font-weight: bold; text-align: center; border: 5px dashed darkgray; } .dropZone-error { background: #faa !important; color: #f00; } </style> <script type="text/javascript"> var timeout; var checkTimer; var channels = {}; var states = {}; var values = {}; var problems = []; var timers = []; var fwLink = ''; var counter = 0; function getComPorts(actualValue) { counter++; if (counter > 20) return; timeout = setTimeout(function () { getComPorts(actualValue); }, 2000); sendTo(null, 'listUart', null, function (list) { if (timeout) { clearTimeout(timeout); timeout = null; } if (!list || !list.length) { setTimeout(function () { getComPorts(actualValue); }, 1000); return; } var text = '<option value="">' + _('Select port') + '</option>'; for (var j = 0; j < list.length; j++) { if (list[j].path === 'Not available') { text += '<option value="" selected>' + _('Not available') + '</option>'; $('#comName').prop('disabled', true); break; } else { text += '<option value="' + list[j].path + '" ' + ((actualValue === list[j].path) ? 'selected' : '') + '>' + list[j].path + '</option>'; } } $('#comName').html(text); }); } function setValue(id, value, onChange) { var $value = $('#' + id + '.value'); if ($value.attr('type') === 'checkbox') { $value.prop('checked', value).on('change', function () { onChange(); }); } else { $value.val(value).on('change', function () { onChange(); }).on('keyup', function () { // Check that only numbers entered if ($(this).hasClass('number')) { var val = $(this).val(); if (val) { var newVal = ''; for (var i = 0; i < val.length; i++) { if (val[i] >= '0' && val[i] <= '9') { newVal += val[i]; } } if (val != newVal) $(this).val(newVal); } } onChange(); }); } } function deleteState(id) { socket.emit('delObject', id, function (err) { socket.emit('delState', id, function (err) { }); }); } function getIntervalAsText(ts) { var minutes = ts ? Math.floor((new Date().getTime() - ts) / 60000) : 0; if (minutes < 0) minutes = 0; if (minutes === 1) { return _('for one minute'); } else if (minutes) { return _('for <b>%s</b> minutes', minutes); } else { return _('just <b>now</b>'); } } function updateIntervals() { $('.last-value').each(function () { var id = $(this).data('id'); $(this).html(getIntervalAsText(values[id].ts)); }); } function showDevice(obj) { if (obj._id === 'rflink.' + instance + '.info') return; var text = ''; var _class = ''; var title = ''; if (obj.native.ID === null || obj.native.ID === undefined || obj.native.ID === '') { _class += 'no-address '; title += (title ? ', ' : '') + _('No address') } if (obj.native.autoPairProblem) { _class += 'auto-pair-problem '; title += (title ? ', ' : '') + _('More than one device with the same parameters'); } text += '<td style="text-align: right; white-space: nowrap;" class="' + _class + '" title="' + title + '">' + obj.native.brand + '</td>' ; text += '<td style="text-align: center;">' + obj.native.index + '</td>'; text += '<td style="text-align: center;"><input class="auto-repair" type="checkbox" data-id="' + obj._id + '" ' + (obj.native.autoRepair ? 'checked' : '') + ' /></td>'; // if (obj.native.offset !== undefined) { // text += '<td style="text-align: center;"><input class="offset" type="input" data-id="' + obj._id + '" value="' + (obj.native.offset || 0) + '" /></td>'; // } else { // text += '<td></td>'; // } // if (obj.native.factor !== undefined) { // text += '<td style="text-align: center;"><input class="factor" type="input" data-id="' + obj._id + '" value="' + (obj.native.factor || 1) + '" /></td>'; // } else { // text += '<td></td>'; // } //text += '<td style="text-align: right;">' + obj.native.ID + '</td>'; text += '<td style="text-align: left;" class="raw-value" data-id="' + obj._id + '">' + showValue(obj._id) + '</td>'; text += '<td style="text-align: center"><button class="pair" data-id="' + obj._id + '"></button></td>'; text += '<td style="text-align: center"><button class="del" data-id="' + obj._id + '"></button></td>'; if (channels[obj._id]) { $('tr[data-channel="' + obj._id + '"]').html(text).removeClass('show-pair-off'); } else { text = '<tr class="device" data-channel="' + obj._id + '">' + text + '</tr>'; $('#devices').append(text); } channels[obj._id] = obj; $('.del[data-id="' + obj._id + '"]').button({ text: false, icons: { primary: 'ui-icon-trash' } }).css({width: 22, height: 22}).unbind('click').click(function () { var id = $(this).data('id'); if (confirm(_('Are you sure?'))) { socket.emit('delObject', id, function () { socket.emit('getObjectView', 'system', 'state', {startkey: id + '.', endkey: id + '.\u9999', include_docs: true}, function (err, res) { for (var i = 0; i < res.rows.length; i++) { deleteState(res.rows[i].id); } $('tr[data-channel="' + id + '"]').remove(); delete channels[id]; }); }); } }); $('.auto-repair[data-id="' + obj._id + '"]').change(function () { var $this = $(this); var id = $this.data('id'); $this.prop('disabled', true); channels[id].native.autoRepair = !channels[id].native.autoRepair; socket.emit('setObject', id, channels[id], function (err) { // button will be re-drawn on change }); }); $('.offset[data-id="' + obj._id + '"]').change(function () { var $this = $(this); var id = $this.data('id'); $this.prop('disabled', true); states[id].native.offset = parseFloat($this.val()); socket.emit('setObject', id, states[id], function (err) { // button will be re-drawn on change }); }); $('.factor[data-id="' + obj._id + '"]').change(function () { var $this = $(this); var id = $this.data('id'); $this.prop('disabled', true); states[id].native.factor = parseFloat($this.val()); socket.emit('setObject', id, states[id], function (err) { // button will be re-drawn on change }); }); var $pair = $('.pair[data-id="' + obj._id + '"]'); $pair.button({ text: false, icons: { primary: 'ui-icon-transfer-e-w' } }).css({width: 22, height: 22}).unbind('click').click(function () { var $this = $(this); var id = $this.data('id'); $this.button('disable'); if (!channels[id].native.pair) { channels[id].native.pair = true; channels[id].native.ID = null; // Reset ID } else { channels[id].native.pair = false; } if (!channels[id].native.autoRepair && channels[id].native.autoPairProblem !== undefined) { delete channels[id].native.autoPairProblem; } socket.emit('setObject', id, channels[id], function (err) { // button will be re-drawn on change }); }); if (obj.native.pair) { $pair.addClass('pair-on'); } var pos; if ((pos = problems.indexOf(obj._id)) !== -1) { $('tr[data-channel="' + obj._id + '"]').addClass('show-pair-off'); problems.splice(pos, 1); } } function showValue(channelId) { // build last value var ids = []; var namespace = channelId + '.'; var len = namespace.length; for (var id in values) { if (values.hasOwnProperty(id) && values[id] && id.substring(0, len) === namespace) ids.push(id); } var value; if (ids.length) { ids.sort(); value = '<span class="last-value" data-id="' + ids[0] + '">' + getIntervalAsText(values[ids[0]].ts) + '</span>'; // build values string for (var j = 0; j < ids.length; j++) { value += (value ? ', ' : '') + '<b>' + states[ids[j]].native.attr + '</b>: ' + values[ids[j]].val; } } return value; } function checkAutoRepairs(callback) { if (checkTimer) clearTimeout(checkTimer); checkTimer = setTimeout(function () { _checkAutoRepairs(callback); }, 1000); } function _checkAutoRepairs(callback, ids) { if (!ids) { ids = []; for (var id in channels) { if (!channels.hasOwnProperty(id) || !channels[id].native || !channels[id].native.brand) continue; ids.push(id); } } if (!ids.length) { if (callback) callback(); return; } var _id = ids.shift(); checkAutoRepair(channels[_id], function () { setTimeout(function () { _checkAutoRepairs(callback, ids); }, 0); }); } function checkAutoRepair(obj, callback) { // autoPairs var pairs = []; var autoRepair = []; for (var __id in channels) { if (!channels.hasOwnProperty(__id) || !channels[__id].native) continue; // If device suits to it if (channels[__id].native.brand === obj.native.brand && channels[__id].native.attrs === obj.native.attrs ) { pairs.push(__id); if (channels[__id].native.autoRepair) autoRepair.push(__id); } } if (pairs.length === 1) { if (channels[pairs[0]].native.autoPairProblem) { delete channels[pairs[0]].native.autoPairProblem; // remove autoPairProblem socket.emit('setObject', pairs[0], channels[pairs[0]], function (err) { // button will be re-drawn on change if (callback) callback (); }); } else if (callback){ callback (); } } else if (pairs.length > 1 && autoRepair.length) { // disable autoRepair by all sensors var count = 0; for (var i = 0; i < autoRepair.length; i++) { channels[autoRepair[i]].native.autoRepair = false; if (channels[autoRepair[i]].native.autoPairProblem) delete channels[autoRepair[i]].native.autoPairProblem; var pos = pairs.indexOf(autoRepair[i]); if (pos !== -1) pairs.splice(pos, 1); count++; problems.push(autoRepair[i]); $('tr[data-channel="' + autoRepair[i] + '"]').removeClass('show-pair-off'); socket.emit('setObject', autoRepair[i], channels[autoRepair[i]], function (err) { // button will be re-drawn on change if (!--count && callback) callback(); }); } for (var j = 0; j < pairs.length; j++) { $('tr[data-channel="' + pairs[j] + '"]').removeClass('show-pair-off'); if (channels[pairs[j]].native.autoPairProblem) { delete channels[autoRepair[i]].native.autoPairProblem; problems.push(pairs[j]); count++; adapter.setForeignObject(pairs[j], channels[pairs[j]], function (err) { if (err) adapter.log.error('Cannot set object: ' + err); if (!--count && callback) callback(); }); } else { (function (__id) { setTimeout(function () { $('tr[data-channel="' + __id + '"]').addClass('show-pair-off'); }, 100); })(pairs[j]); } } if (!count && callback) callback(); } else if (callback){ callback (); } } function flash(hex) { sendTo(null, 'flash', {hex: hex}, function (result) { $('#drop-zone').hide(); if (result.error) { showMessage(_('Cannot flash: ') + (result.error.message || result.error), _('Flash error')); } else { showMessage(_('File was successfully flashed'), _('Success')); } $('#flash_default').prop('disabled', false); $('#flashFile').prop('disabled', false); $('#drop-text').html(_('Drop the files here')); }); } function fileHandler(event) { event.preventDefault(); var file = event.dataTransfer ? event.dataTransfer.files[0] : event.target.files[0]; var $dz = $('#drop-zone'); if (file.size > 10000000) { $('#drop-text').html(_('File is too big!')); $dz.addClass('dropZone-error').animate({opacity: 0}, 1000, function () { $dz.hide().removeClass('dropZone-error').css({opacity: 1}); showMessage(_('File is too big!')); $('#drop-text').html(_('Drop the files here')); }); $('#flashFile').replaceWith($('#flashFile').clone(true)); return false; } if (file.name.toLowerCase().split('.').pop() !== 'hex') { $('#drop-text').html(_('invalid_extension')); $dz.addClass('dropZone-error').animate({opacity: 0}, 1000, function () { $dz.hide().removeClass('dropZone-error').css({opacity: 1}); showMessage(_('invalid_extension')); $('#drop-text').html(_('Drop the files here')); }); $('#flashFile').replaceWith($('#flashFile').clone(true)); return false; } $dz.show(); $('#flash_default').prop('disabled', true); $('#flashFile').prop('disabled', true); $('#drop-text').html(_('Flashing... Please wait')); var reader = new FileReader(); reader.onload = function (evt) { var text; try { text = evt.target.result.split(',')[1]; // string has form data:;base64,TEXT== } catch(err) { $('#flash_default').prop('disabled', false); $('#flashFile').prop('disabled', false); $('#drop-text').html(_('Cannot read file!')); $dz.addClass('dropZone-error').animate({opacity: 0}, 1000, function () { $dz.hide().removeClass('dropZone-error').css({opacity: 1}); main.showError(_('Cannot read file!')); $('#drop-text').html(_('Drop the files here')); }); return; } if (confirmMessage) { confirmMessage(_('Flash will start immediately. Are you sure?'), _('Question'), 'alert', function (result) { if (result) flash(text); }); } else { flash(text); } }; reader.readAsDataURL(file); } function defaultFlash(isAsked) { if (!isAsked && confirmMessage) { confirmMessage(_('Flash will start immediately. Are you sure?'), _('Question'), 'alert', function (result) { if (result) defaultFlash(true); }); } else { $('#drop-zone').show(); $('#flash_default').prop('disabled', true); $('#flashFile').prop('disabled', true); $('#drop-text').html(_('Flashing... Please wait')); flash(); } } function load(settings, onChange) { if (!settings) return; for (var key in settings) { if (!settings.hasOwnProperty(key)) continue; setValue(key, settings[key], onChange); } $('#enableInclusion').button().hide(); $('#tabs').show().tabs({ activate: function (event, ui) { if (ui.newPanel.attr('id') === 'tabs-3') { $('#drop-zone').show().css({opacity: 1}).animate({opacity: 0}, 2000, function () { $('#drop-zone').hide().css({opacity: 1}); }); } } }); setTimeout(function () { socket.emit('getState', adapter + '.' + instance + '.inclusionOn', function (err, state) { if (err) window.alert(err); $('#enableInclusion').button('option', 'label', state && state.val ? _('Disable inclusion mode') : _('Enable inclusion mode')).show().click(function () { socket.emit('getState', adapter + '.' + instance + '.inclusionOn', function (err, state) { state = state || {val: false}; state.val = !state.val; $('#enableInclusion').button('option', 'label', state && state.val ? _('Disable inclusion mode') : _('Enable inclusion mode')); socket.emit('setState', adapter + '.' + instance + '.inclusionOn', { val: state.val, ack: false }, function (err) { if (!err) { showMessage(state.val ? _('Inclusion mode is active') : _('Inclusion mode is inactive')); } else { showError(err); } }); }); }); }); }, 1000); $('#flash_default').button().click(function () { defaultFlash(); }); getIsAdapterAlive(function (isAlive) { if (isAlive || common.enabled) { $('#not-started').hide(); $('#flash_default').prop('disabled', false); getComPorts(settings.comName); var $dropZone = $('#tabs-3'); if (typeof(window.FileReader) !== 'undefined' && !$dropZone.data('installed')) { $dropZone.data('installed', true); var $dz = $('#drop-zone'); $('#drop-text').html(_('Drop the files here')); $dropZone[0].ondragover = function() { $dz.unbind('click'); $dz.show(); return false; }; $dz.click(function () { $dz.hide(); }); $dz[0].ondragleave = function() { $dz.hide(); return false; }; $dz[0].ondrop = fileHandler; } $('#flashFile').change(fileHandler); } else { $('#flashFile').prop('disabled', true); $('#flash_default').prop('disabled', true); $('#not-started').show(); } }); socket.emit('getObjectView', 'system', 'channel', {startkey: 'rflink.' + instance + '.', endkey: 'rflink.' + instance + '.\u9999', include_docs: true}, function (err, res) { socket.emit('getObjectView', 'system', 'state', {startkey: 'rflink.' + instance + '.', endkey: 'rflink.' + instance + '.\u9999', include_docs: true}, function (err, _states) { socket.emit('getStates', function (err, _values) { var namespace = 'rflink.' + instance + '.'; var len = namespace.length; for (var id in _values) { if (id.substring(0, len) === namespace) { values[id] = _values[id]; } } if (_states && _states.rows && _states.rows.length) { for (var j = 0; j < _states.rows.length; j++) { states[_states.rows[j].id] = _states.rows[j].value; } } res.rows.sort(function (a, b) { if (a.value.native.brand > b.value.native.brand) return 1; if (a.value.native.brand < b.value.native.brand) return -1; return 0; }); for (var i = 0; i < res.rows.length; i++) { showDevice(res.rows[i].value); } updateVersion(); checkAutoRepairs(); setInterval(updateIntervals, 10000); }); }); }); socket.on('objectChange', function (id, obj) { if (!obj) { $('tr[data-channel="' + id + '"]').remove(); if (channels[id]) { console.log('Device deleted: ' + id); delete channels[id]; checkAutoRepairs(); } else if (states[id]) { console.log('State deleted: ' + id); delete states[id]; } } else { if (obj.type === 'channel' && obj.native && obj.native.brand) { if (channels[id]) { console.log('Device changed: ' + id + ': ' + JSON.stringify(obj.native)); } else { console.log('New device: ' + id + ': ' + JSON.stringify(obj.native)); } showDevice(obj); checkAutoRepairs(); } else if (obj.type === 'state' && obj.native && obj.native.brand) { if (states[id]) { console.log('State changed: ' + id + ': ' + JSON.stringify(obj.native)); } else { console.log('New State: ' + id + ': ' + JSON.stringify(obj.native)); } states[id] = obj; } } }); socket.on('stateChange', function (id, state) { if (id === 'rflink.' + instance + '.firmwareVersion' || id === 'rflink.' + instance + '.availableVersion') { values[id] = state; updateVersion(); } else if (id === 'rflink.' + instance + '.inclusionOn') { values[id] = state; $('#enableInclusion').button('option', 'label', state && state.val ? _('Disable inclusion mode') : _('Enable inclusion mode')); } else if (id === 'rflink.' + instance + '.rawData') { // analyse rawData if (!state || !state.val || !state.ack || typeof state.val !== 'string') return; // received something like: // UPM/Esic;ID=0001;TEMP=00cf;HUM=16;BAT=OK; /*var frame = parseString(state.val); if (!frame) return; console.log('Incoming data: ' + JSON.stringify(frame)); for (var _id in channels) { if (!channels.hasOwnProperty(_id) || !channels[_id].native) continue; if (channels[_id].native.brand === frame.brandRaw && channels[_id].native.ID === frame.ID && (frame.SWITCH === undefined || (channels[_id].native.switches && channels[_id].native.switches.indexOf(frame.SWITCH) !== -1)) ) { delete frame.ID; delete frame.brand; delete frame.brandRaw; var text = getIntervalAsText(_id) + ', '; text += '<span class="highlight">' + stringifyFrame(frame) + '</span>'; $('.raw-value[data-id="' + _id + '"]').html(text); return; } } */ } else { if (id.substring(0, ('rflink.' + instance + '.').length) !== 'rflink.' + instance + '.') return; values[id] = state; var pos = id.lastIndexOf('.'); id = id.substring(0, pos); if (id === 'rflink.' + instance + '.info' || id === 'rflink.' + instance + '.rawData') return; if (timers[id]) clearTimeout(timers[id]); (function (_id) { timers[_id] = setTimeout(function () { timers[_id] = null; $('.raw-value[data-id="' + _id + '"]').html('<span class="highlight">' + showValue(_id, true) + '</span>'); }, 200); })(id); } }); socket.emit('subscribeObjects', 'rflink.' + instance + '.*'); socket.emit('subscribeStates', 'rflink.' + instance + '.*'); $('#comName').change(function () { socket.emit('getState', adapter + '.' + instance + '.inclusionOn', function (err, state) { if (!state || !state.val) { $('#enableInclusion').button('option', 'label', _('Disable inclusion mode')); socket.emit('setState', adapter + '.' + instance + '.inclusionOn', { val: true, ack: false }, function (err) { if (!err) { showMessage(state.val ? _('Inclusion mode is active') : _('Inclusion mode is inactive')); } else { showError(err); } }); } }); }); sendTo(null, 'readNewVersion', null, function (result) { fwLink = result ? result.fwLink : null; }); onChange(false); } function updateVersion() { var actual; if (values['rflink.' + instance + '.firmwareVersion']) { actual = values['rflink.' + instance + '.firmwareVersion'].val; $('#actual_version').html(actual); //"V1.1 - R44" if (actual.toString().indexOf('-') !== -1) { var parts = actual.split('-'); actual = parseInt(parts[1].trim().replace('R', ''), 10); } } if (values['rflink.' + instance + '.availableVersion']) { $('#new_version').html(values['rflink.' + instance + '.availableVersion'].val); } if (values['rflink.' + instance + '.availableVersion'] && actual) { if (parseInt(values['rflink.' + instance + '.availableVersion'].val, 10) > actual) { $('#flash_tab a').css('color', 'green'); $('#flash_button').show(); $('#info_newest').hide(); } else { $('#flash_button').hide(); $('#info_newest').show(); $('#flash_tab a').css('color', ''); } } } function save(callback) { var obj = {}; $('.value').each(function () { var $this = $(this); if ($this.attr('type') === 'checkbox') { obj[$this.attr('id')] = $this.prop('checked'); } else { obj[$this.attr('id')] = $this.val(); } }); callback(obj); } </script> <style type="text/css"> .tab1 { border: 1px solid blue; width: 95%; overflow: auto; } .help { font-size: small; } </style> <div id="adapter-container" style="width: 100%; height: 100%; overflow: hidden"> <div id="tabs" style="width: 100%; height: 100%; overflow: hidden; display: none;"> <ul> <li><a href="#tabs-1" class="translate">Options</a></li> <li><a href="#tabs-2" class="translate">Devices</a></li> <li id="flash_tab"><a href="#tabs-3" class="translate">Flash Arduino</a></li> </ul> <div id="tabs-1"> <table><tr><td><img src="rflink.png"></td><td><h3 class="translate">RFLink adapter settings</h3></td></tr></table> <table> <tr class="serial"><td><label for="comName" class="translate">Com port:</label></td><td><select class="value oneWidth" id="comName"></select></td><td></td></tr> <tr class="serial"><td><label for="baudRate" class="translate">Baud rate:</label></td><td><select class="value oneWidth" id="baudRate"> <option value="110">110</option> <option value="150">150</option> <option value="300">300</option> <option value="600">600</option> <option value="1200">1200</option> <option value="2400">2400</option> <option value="4800">4800</option> <option value="9600">9600</option> <option value="19200">19200</option> <option value="38400">38400</option> <option value="56000">56000</option> <option value="57600">57600</option> <option value="115200">115200</option> </select></td><td></td></tr> <tr class="serial"><td><label for="board" class="translate">Board type:</label></td><td> <select class="value" id="board"> <option value="uno">Arduino Uno</option> <option value="mega">Arduino Mega</option> <option value="leonardo">Arduino Leonardo</option> <option value="micro">Arduino Micro</option> <option value="nano">Arduino Nano</option> <option value="duemilanove168">Arduino Duemilanove</option> <option value="blend-micro">RedBearLab Blend Micro</option> <option value="tinyduino">Tiny Circuits Tinyduino</option> <option value="sf-pro-micro">SparkFun Pro Micro</option> <option value="qduino">Qtechknow Qduino</option> <option value="pinoccio">Pinoccio Scout</option> <option value="imuduino">Femtoduino IMUduino</option> <option value="feather">Adafruit Feather 32u4 Basic Proto</option> <option value="arduboy">Arduboy</option> </select> </td> <td></td> </tr> <tr><td><label for="connTimeout" class="translate">Connection timeout:</label></td><td><input class="value oneWidth" id="connTimeout" /></td><td class="translate">ms</td></tr> <tr><td><label for="inclusionTimeout" class="translate">Inclusion mode timeout:</label></td><td><input class="value oneWidth" id="inclusionTimeout" /></td><td><span class="translate">inclusion help</span></td></tr> <!--tr><td><label for="autoRepair" class="translate">Timeout for auto re-pair:</label></td><td><input class="value oneWidth" id="autoRepair" /></td><td><span class="translate">re-pair help</span></td></tr--> <tr><td></td><td colspan="2"><button id="enableInclusion" class="translateB">Enable inclusion mode</button><div id="inclusionState"></div></td></tr> </table> </div> <div id="tabs-2" style="width: 100%; height: calc(100% - 40px); overflow-x: hidden; overflow-y: auto; padding: 0"> <table style="width: 100%;"> <thead> <tr class="ui-widget-header"> <td style="width: 100px; text-align: center; white-space: nowrap; white-space: nowrap" class="translate">Brand</td> <td style="width: 70px; text-align: center; white-space: nowrap" class="translate">Number</td> <td style="width: 50px; text-align: center; white-space: nowrap" class="translate">Auto re-pair</td> <!--td style="width: 50px; text-align: center; white-space: nowrap" class="translate">Offset</td> <td style="width: 50px; text-align: center; white-space: nowrap" class="translate">Factor</td--> <!--td style="width: 50px; text-align: center" class="translate">ID</td--> <td style="width: 200px; text-align: left; white-space: nowrap" class="translate">Values</td> <td style="width: 30px; text-align: center; white-space: nowrap" class="translate">Pair</td> <td style="width: 30px; text-align: center; white-space: nowrap" class="translate"></td> </tr> </thead> <tbody id="devices"> </tbody> </table> </div> <div id="tabs-3" style="width: 100%; height: 100%;display: none"> <div id="drop-zone"> <div style="padding-top: 15%" class="translate" id="drop-text">Drop the files here</div> </div> <p class="translate">Upload sketch HEX File for RFLink: </p> <p> <input type="file" id="flashFile"/> <div id="not-started" class="translate">not-started</div> </p> <p><span class="translate">Actual version: </span><span id="actual_version">???</span>, <span class="translate">Available version: </span><span id="new_version">???</span></p> <p id="flash_button"> <button id="flash_default" class="translate">Flash newest sketch</button> </p> <p id="info_newest" class="translate" style="display: none; color: green">You have newest version.</p> </div> </div> </div> </html>