iobroker.rflink
Version:
ioBroker RFLink Adapter
898 lines (817 loc) • 37.5 kB
HTML
<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) ;
}
.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 ;
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>