UNPKG

iobroker.fb-checkpresence

Version:

The adapter checks the presence of family members over the fritzbox. You must fill in the name of the family member and the mac-address of the used device. The comment is optional and you can enable or disable the family member. The datapoint based on the

708 lines (660 loc) 31.2 kB
'use strict'; /* eslint-disable no-irregular-whitespace */ /* eslint-disable-next-line no-undef */ /* eslint-env jquery, browser */ // https://eslint.org/docs/user-guide/configuring#specifying-environments /* global sendTo, getEnums, common, systemLang, socket, values2table, table2values, M, _, instance */ // for eslint /*eslint no-undef: "error"*/ /*eslint-env browser*/ const adapterNamespace = `fb-checkpresence.${instance}`; let familymembers = []; let whitelist = []; let arr; let active = false; if (typeof _ !== 'function') _ = translateWord; function search(event) { const input = document.getElementById(event.currentTarget.id); const filter = input.value.toUpperCase(); let table = null; if( event.currentTarget.id == 'searchDevice'){ table = document.getElementById('tabDevices'); // Enable "reset search" button $('button#btnResetSearch').attr('disabled', false); } if( event.currentTarget.id == 'searchWL'){ table = document.getElementById('tabWl'); $('button#btnResetSearchWl').attr('disabled', false); } const tr = table.getElementsByTagName('tr'); // Loop through all table rows, and hide those who don't match the search query for (let i = 0; i < tr.length; i++) { const td = tr[i].getElementsByTagName('td')[1]; //search in second column if (td) { const txtValue = td.textContent || td.innerText; if (txtValue.toUpperCase().indexOf(filter) > -1) { tr[i].style.display = ''; } else { tr[i].style.display = 'none'; } } } } /*function setValue(id, value, onChange) { const $value = $('#' + id + '.value'); if ($value.attr('type') === 'checkbox') { $value.prop('checked', value).change(function() { onChange(); }); } else { const val = $value.data('crypt') && value ? decrypt(secret, value) : value; $value.val(val).change(function() { onChange(); }).keyup(function() { // Check that only numbers entered if ($(this).hasClass('number')) { const val = $(this).val(); if (val) { let newVal = ''; for (let i = 0; i < val.length; i++) { if (val[i] >= '0' && val[i] <= '9') { newVal += val[i]; } } if (val != newVal) $(this).val(newVal); } } onChange(); }); } }*/ async function getHistoryInstances(settings){ let histArr =[]; histArr = await getHistoryAdapter('history', histArr); histArr = await getHistoryAdapter('sql', histArr); histArr = await getHistoryAdapter('influxdb', histArr); const selectElement = document.getElementById('history'); const cnfHistory = settings.history; let option = document.createElement('option'); option.text = 'disabled'; option.value = ''; selectElement.options[0] = option; for (let i = 0; i < histArr.length; i++) { option = document.createElement('option'); const str = histArr[i].name.replace('system.adapter.', ''); option.text = str; option.value = str; selectElement.options[i+1] = option; if (cnfHistory == str){ selectElement.selectedIndex = i+1; } } $('select').select(); } function getHistoryAdapter (adapter, hist) { return new Promise((resolve, reject) => { getAdapterInstances(adapter, function (arr) { for (let i = 0; i < arr.length; i++) { hist.push({'name' : arr[i]._id}); } resolve(hist); }); }); } // Field is valid? function chkValidity() { let valid = true; $('.value').each(function() { const $key = $(this); const element = document.getElementById($key.attr('id')); if ($key.attr('type') !== 'checkbox' && !element.checkValidity()) { valid = false; } }); return valid; } function dlgError(text){ const content = '<div class="modal-header">' + '<h6 class="dlgErrorTitle"><span>' + _('Error') + '</span></h6>' + '</div>' + '<div class="modal-content">' + '<p class="dlgErrorText">' + _(text) + '</p>' + '</div>' + '<div class="modal-footer">' + '<a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-close"><i class="large material-icons left">close</i><span class="translate">' + _('Close') + '</span></a>' + '</div>'; $('#dlgDevices').html(content); $('#dlgDevices').modal(); $('#dlgWL').html(content); $('#dlgWL').modal(); } function dlgDevicesOld(arr, title, id){ let tableBodyDevices = ''; arr.forEach(function (element) { const chkVal2 = ''; //onMessage -> allDevices name, mac, ip -> see main.js tableBodyDevices += '<tr class="add-device" ' + 'data-macaddress="' + (element.mac || '') + '" ' + 'data-familymember="' + (element.name || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '" ' + 'data-ip="' + (element.ip || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '">' + '<td class="valign-wrapper"><label><input class="filled-in" type="checkbox" name="chkFM"' + chkVal2 + ' /><span></span></label></td>' + '<td>' + element.name + '</td>' + '<td class="center">' + element.mac + '</td>' + '<td class="center">' + element.ip + '</td>' + '</tr>'; }); const dialogDevices = '<div class="modal-header">' + '<h6 class="dlgTitle"><span class="translate">' + _(title) + '</span></h6>' + '<div class="input-field inline">' + '<i id="searchIcon" class="material-icons prefix">search</i>' + '<button id="btnResetSearch" disabled="disabled" class="btn-floating btn-small waves-effect waves-green"><i class="material-icons">clear</i></button>' + '<input id="searchDevice" name="search" class="validate searchInput" type="text" onkeyup="search(event)">' + '<label class="searchLabel" for="searchDevice">' + _('Search for device') + '..' + '</label>' + '</div>' + '<div>' + '<table class="fm">' + '<thead>' + '<tr class="header">' + '<th class="valign-wrapper header"><label class="header"><input type="checkbox" class="cb filled-in header" id="select-all" onclick="select-all(event)"/><span></span></label></th>' + '<th class="header left-align">' + 'Hostname' + '</th>' + '<th class="header center-align">' + _('Mac-address') + '</th>' + '<th class="header center-align">' + _('Ip-address') + '</th>' + '</tr>' + '</thead>' + '</table>' + '</div>' + '</div>' + '<div class="modal-content">' + '<div>' + '<table class="fm" id="tabDevices">' + '<tbody>' + tableBodyDevices + '</tbody>' + '</table>' + '</div>' + '</div>' + '<div class="modal-footer">' + '<a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-set" id="save"><i class="large material-icons left">add</i><span class="translate">' + _('Add') + '</span></a>' + '<a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-close"><i class="large material-icons left">close</i><span class="translate">' + _('Close') + '</span></a>' + '</div>'; $(id).html(dialogDevices); $(id).modal({dismissible: false}); } function dlgDevices(arr, title, id) { const tableRows = arr.map(function (element) { const chkVal2 = ''; // onMessage -> allDevices name, mac, ip -> see main.js return ` <tr class="add-device" data-macaddress="${element.mac || ''}" data-familymember="${(element.name || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"')}" data-ip="${(element.ip || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"> <td class="valign-wrapper"><label><input class="filled-in" type="checkbox" name="chkFM"${chkVal2} /><span></span></label></td> <td>${element.name}</td> <td class="center">${element.mac}</td> <td class="center">${element.ip}</td> </tr>`; }); const tableBodyDevices = tableRows.join(''); const dialogDevices = ` <div class="modal-header"> <h6 class="dlgTitle"><span class="translate">${_(title)}</span></h6> <div class="input-field inline"> <i id="searchIcon" class="material-icons prefix">search</i> <button id="btnResetSearch" disabled="disabled" class="btn-floating btn-small waves-effect waves-green"><i class="material-icons">clear</i></button> <input id="searchDevice" name="search" class="validate searchInput" type="text" onkeyup="search(event)"> <label class="searchLabel" for="searchDevice">${_('Search for device')}..</label> </div> <div> <table class="fm"> <thead> <tr class="header"> <th class="valign-wrapper header"><label class="header"><input type="checkbox" class="cb filled-in header" id="select-all" onclick="select-all(event)"><span></span></label></th> <th class="header left-align">Hostname</th> <th class="header center-align">${_('Mac-address')}</th> <th class="header center-align">${_('Ip-address')}</th> </tr> </thead> </table> </div> </div> <div class="modal-content"> <div> <table class="fm" id="tabDevices"> <tbody> ${tableBodyDevices} </tbody> </table> </div> </div> <div class="modal-footer"> <a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-set" id="save"><i class="large material-icons left">add</i><span class="translate">${_('Add')}</span></a> <a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-close"><i class="large material-icons left">close</i><span class="translate">${_('Close')}</span></a> </div>`; $(id).html(dialogDevices); $(id).modal({dismissible: false}); } function dlgWl(arr, title, id){ let tableBodyWl = ''; arr.forEach(function (element) { let chkVal = ''; for(let i=0; i < whitelist.length; i++){ if (element.mac == whitelist[i].white_macaddress){ chkVal = 'checked'; break; } } //onMessage -> allDevices name, mac, ip -> see main.js tableBodyWl += '<tr ' + 'data-white_macaddress="' + (element.mac || '') + '" ' + 'data-white_device="' + (element.name || '').replace(/"/g, '\\"') + '">' + '<td class="valign-wrapper"><label><input class="filled-in" type="checkbox" name="chkWL"' + chkVal + ' /><span></span></label></td>' + '<td>' + element.name + '</td>' + '<td class="center">' + element.mac + '</td>' + '</tr>'; }); const dialogWl= '<div class="modal-header">' + '<h6 class="dlgTitle"><span class="translate">' + _(title) + '</span></h6>' + '<div class="input-field inline">' + '<i id="searchIcon" class="material-icons prefix">search</i>' + '<button id="btnResetSearchWL" disabled="disabled" class="btn-floating btn-small waves-effect waves-green"><i class="material-icons">clear</i></button>' + '<input id="searchWL" name="search" class="validate searchInput" type="text" onkeyup="search(event)">' + '<label class="searchLabel" for="searchWL">' + _('Search for device') + '..' + '</label>' + '</div>' + '<div>' + '<table class="wl">' + '<thead>' + '<tr class="header">' + '<th class="header valign-wrapper"><label><input type="checkbox" class="filled-in" id="select-all2" onclick="select-all(event)"/><span></span></label></th>' + '<th class="header left-align">' + 'Hostname' + '</th>' + '<th class="header center-align">' + _('Mac-address') + '</th>' + '</tr>' + '</thead>' + '</table>' + '</div>' + '</div>' + '<div class="modal-content col s12 translate">' + '<div>' + '<table class="wl" id="tabWl">' + '<tbody>' + tableBodyWl + '</tbody>' + '</table>' + '</div>' + '</div>' + '<div class="modal-footer">' + '<a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-set" id="save1"><i class="large material-icons left">add</i><span class="translate">' + _('Add') + '</span></a>' + '<a class="btnDlg modal-action modal-close waves-effect waves-green btn-small btn-close"><i class="large material-icons left">close</i><span class="translate">' + _('Close') + '</span></a>' + '</div>'; $(id).html(dialogWl); $(id).modal({dismissible: false,}); } // This will be called by the admin adapter when the settings page loads async function load(settings, onChange) { try { if (!settings) return; //$('.hideOnLoad').hide(); familymembers = settings.familymembers || []; whitelist = settings.whitelist || []; values2table('values', familymembers, onChange, tableOnReady); values2table('whitevalues', whitelist, onChange); getHistoryInstances(settings); //fill select options // Secret für Passwortverschlüsselung abfragen //const obj = await emitAsync('getObject', 'system.config'); //if (obj){ //secret = (obj.native ? obj.native.secret : '') || 'SdoeQ85NTrg1B0FtEyzf'; $('.value').each(function () { const $key = $(this); const id = $key.attr('id'); if ($key.attr('type') === 'checkbox') { // do not call onChange direct, because onChange could expect some arguments $key.prop('checked', settings[id]).on('change', function(){ if (chkValidity()) { onChange(); } else { onChange(false); } }); //=> onChange()) } else { let val; if ($key.data('crypt') =='1'){ //val = decrypt(secret, settings[id]) ; val = settings[id]; } else{ val = settings[id]; } $key.val(val).on('change', function(){ //=> onChange()) if (chkValidity()) { onChange(); } else { onChange(false); } }).on('keyup', function(){ //=> onChange()) if (chkValidity()) { onChange(); } else { onChange(false); } }); } }); //} $('select').select(); if (M) M.updateTextFields(); onChange(false); // if adapter is alive const state = await emitAsync('getState', 'system.adapter.' + adapter + '.' + instance + '.alive'); active = (state && state.val); if (!active) { dlgError('You have to start your ioBroker.' + adapter + ' adapter before you can use this function!'); }else{ const g_onChange = onChange; const result = await sendToAsync('getDevices', { onlyActive: true, reread: true }); if (result != null) { arr = JSON.parse(result); if(arr || arr.result == true){ dlgDevices(arr, 'Add family member', '#dlgDevices'); dlgWl(arr, 'Add a device', '#dlgWL'); }else{ dlgError('Can not read devices! Result = false'); return false; } $('#save1').click(function () { // Loop through all checkboxes, and add all devices with selected checkboxes whitelist = []; //clear whitelist $('#tabWL input[type=checkbox]:checked').each(function () { const row = $(this).closest('tr')[0]; const mac = $(row).data('white_macaddress'); const device = $(row).data('white_device'); if (device != null){ whitelist.push({white_macaddress: mac, white_device: device}); values2table('whitevalues', whitelist, g_onChange); g_onChange(true); } }); }); $('#save').click(function () { // Loop through all checkboxes, and add all devices with selected checkboxes const devices = []; //clear whitelist //familymembers = settings.familymembers || []; familymembers = table2values('values') || []; $('#tabDevices input[type=checkbox]:checked').each(function () { const row = $(this).closest('tr')[0]; const ip = $(row).data('ip'); const mac = $(row).data('macaddress'); const device = $(row).data('familymember'); if (device != undefined){ let comment = ''; let enabled = true; let famname = device; let usefilter = false; let usage = 'MAC'; let group = ''; for (let i=0; i<familymembers.length; i++){ usage = familymembers[i].usage; if(usage == 'MAC'){ if (familymembers[i].macaddress == mac){ //device = familymembers[i].familymember; enabled = familymembers[i].enabled; comment = familymembers[i].comment; usefilter = familymembers[i].usefilter; famname = familymembers[i].familymember; usage = familymembers[i].usage; group = familymembers[i].group; break; } } if(usage == 'IP'){ if (familymembers[i].ipaddress == ip){ //device = familymembers[i].familymember; enabled = familymembers[i].enabled; comment = familymembers[i].comment; usefilter = familymembers[i].usefilter; famname = familymembers[i].familymember; usage = familymembers[i].usage; group = familymembers[i].group; break; } } if(usage == 'Hostname'){ if (familymembers[i].devicename == device){ //device = familymembers[i].familymember; enabled = familymembers[i].enabled; comment = familymembers[i].comment; usefilter = familymembers[i].usefilter; famname = familymembers[i].familymember; usage = familymembers[i].usage; group = familymembers[i].group; break; } } } devices.push({group: group, devicename: device, macaddress: mac, ipaddress: ip, usage: usage, usefilter: usefilter, enabled: enabled, familymember: famname, comment: comment}); } }); for (let i=0; i<familymembers.length; i++){ let enabled = familymembers[i].enabled; let comment = ''; let famname = ''; let usefilter = false; let usage = 'MAC'; let group = ''; let mac; let ip; let device; if(enabled === false){ device = familymembers[i].devicename; mac = familymembers[i].macaddress; ip = familymembers[i].ipaddress; enabled = familymembers[i].enabled; comment = familymembers[i].comment; usefilter = familymembers[i].usefilter; famname = familymembers[i].familymember; usage = familymembers[i].usage; group = familymembers[i].group; devices.push({group: group, devicename: device, macaddress: mac, ipaddress: ip, usage: usage, usefilter: usefilter, enabled: enabled, familymember: famname, comment: comment}); } } values2table('values', devices, g_onChange, tableOnReady); g_onChange(true); }); $('#select-all').click(function(event) { if(this.checked) { // Iterate each checkbox const checkboxes = document.querySelectorAll('input[name="chkFM"]'); for (let i=0; i<checkboxes.length; i++) { checkboxes[i].checked = true; } } else { const checkboxes = document.querySelectorAll('input[name="chkFM"]'); for (let i=0; i<checkboxes.length; i++) { checkboxes[i].checked = false; } } }); $('#select-all2').click(function(event) { if(this.checked) { // Iterate each checkbox const checkboxes = document.querySelectorAll('input[name="chkWL"]'); for (let i=0; i<checkboxes.length; i++) { checkboxes[i].checked = true; } } else { const checkboxes = document.querySelectorAll('input[name="chkWL"]'); for (let i=0; i<checkboxes.length; i++) { checkboxes[i].checked = false; } } }); $('button#btnResetSearch').click(function(){ $('input[name=search]').val(''); const table = document.getElementById('tabDevices'); const tr = table.getElementsByTagName('tr'); // Loop through all table rows, and hide those who don't match the search query for (let i = 0; i < tr.length; i++) { tr[i].style.display = ''; } $('button#btnResetSearch').attr('disabled', true); }); $('button#btnResetSearchWl').click(function(){ $('input[name=search]').val(''); const table = document.getElementById('tabWl'); const tr = table.getElementsByTagName('tr'); // Loop through all table rows, and hide those who don't match the search query for (let i = 0; i < tr.length; i++) { tr[i].style.display = ''; } $('button#btnResetSearchWl').attr('disabled', true); }); }else{ dlgError('Can not read devices! Result = null'); } } // reinitialize all the Materialize labels on the page if you are dynamically adding inputs: //$('.showOnLoad').show(); } catch (e) { dlgError('Cannot find any device! ' + e.message); return; } } //dependency between fbdevices and meshinfo //checking of meshinfo only valid if fbdevices are selected $(document).ready(function(){ //includeHTML(); document.getElementById('buttonadd').addEventListener('click', beforeOpen); $('#newfilter').change(function() { const x = document.getElementById('history'); if(x.selectedIndex === 0){ alert('Please choose HISTORY Adapter first! Option could not be selected'); this.checked = false; } }); $('#meshinfo').change(function() { if(this.checked == true) { const x = document.getElementById('fbdevices'); x.checked = true; } }); /*$('#guestinfo').change(function() { if(this.checked == true) { const x = document.getElementById('fbdevices'); x.checked = true; } });*/ $('#fbdevices').change(function() { if(this.checked == false) { let x = document.getElementById('meshinfo'); x.checked = false; //x = document.getElementById('guestinfo'); //x.checked = false; } }); $('.collapsible').collapsible(); $('.tooltipped').tooltip(); if (M) M.updateTextFields(); }); function beforeOpen(){ // check checkboxes const fm = table2values('values') || []; for(let i = 0; i<fm.length;i++){ //alert(' ' + fm[i].devicename + ' ' + fm[i].enabled); $('#tabDevices input[type=checkbox]').each(function () { const row = $(this).closest('tr')[0]; const mac = $(row).data('macaddress'); const ip = $(row).data('ip'); const dn = $(row).data('familymember'); //const usage = $(row).data('usage'); if (mac && mac == fm[i].macaddress && fm[i].enabled === false){ $(this).prop('checked', false); } if (mac && mac == fm[i].macaddress && fm[i].usage === 'MAC' && fm[i].enabled === true){ $(this).prop('checked', true); } if (ip && ip == fm[i].ipaddress && fm[i].usage === 'IP' && fm[i].enabled === true){ $(this).prop('checked', true); } if (dn && dn == fm[i].devicename && mac && mac == fm[i].macaddress && fm[i].usage === 'Hostname' && fm[i].enabled === true){ $(this).prop('checked', true); } }); } // Open add dialog let elems = document.getElementById('dlgDevices'); let instance = M.Modal.getInstance(elems); instance.open(); elems = document.getElementById('dlgWl'); instance = M.Modal.getInstance(elems); instance.open(); //instance.destroy(); } function tableOnReady() { $('#values .table-values .values-buttons[data-command="delete"]').on('click', function () { const id = $(this).data('index'); const mac = $('#values .values-input[data-name="macaddress"][data-index="' + id + '"]').val(); $('#tabDevices input[type=checkbox]:checked').each(function () { const row = $(this).closest('tr')[0]; const dlgMac = $(row).data('macaddress'); if (mac == dlgMac){ $(this).prop('checked', false); } }); }); } // This will be called by the admin adapter when the user presses the save button function save(callback) { // example: select elements with class=value and build settings object const obj = {}; $('.value').each(function () { const $this = $(this); switch ($this.attr('type')) { case 'checkbox': obj[$this.attr('id')] = $this.prop('checked'); break; case 'number': obj[$this.attr('id')] = parseInt($this.val(), 10); break; default: //obj[$this.attr('id')] = $this.data('crypt') && $this.val() ? encrypt(secret, $this.val()) : $this.val(); obj[$this.attr('id')] = $this.val(); break; } }); // Get table obj.familymembers = table2values('values'); obj.whitelist = table2values('whitevalues'); callback(obj); } function sendToAsync(cmd, obj) { return new Promise((resolve, reject) => { sendTo(adapterNamespace, cmd, obj, (result) => { if (result.error) { //console.error('sendToAsync(): ' + result.error); reject(null); } else { resolve(result); } }); }); } function emitAsync(func, id) { return new Promise((resolve, reject) => { socket.emit(func, id, (err, stateObj) => { if (err) { console.error('emitAsync(): ' + err); reject(null); } else { resolve(stateObj); } }); }); }