iobroker.enocean
Version:
Connects EnOcean devices via USB/Serial devices with TCM300 Chips
629 lines (536 loc) • 20 kB
HTML
<html lang="EN">
<head>
<!-- Load ioBroker scripts and styles-->
<link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
<link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css">
<script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="../../socket.io/socket.io.js"></script>
<script type="text/javascript" src="../../js/translate.js"></script>
<script type="text/javascript" src="../../lib/js/materialize.js"></script>
<script type="text/javascript" src="../../js/adapter-settings.js"></script>
<script type="text/javascript" src="../../lib/js/showdown.min.js"></script>
<!-- Load our own files -->
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="words.js"></script>
<script type="text/javascript" src="components.js"></script>
<script type="text/javascript" src="github.js"></script>
<script type="text/javascript">
let eepList, deviceList, sysConfig;
let eepArray = [];
let mfrArray = [];
let deviceArray = [];
let eepListFilled = false;
let mfrListFilled = false;
let devices = {};
let deviceCommands = {
"delete": {}
};
let instances;
/**
* Get available serial ports and add them to dropdown. If possible the port will be preselected.
* @param {object} settings - The adapter settings object
*/
function getComPorts(settings) {
sendTo(null, 'listSerial', null, (list) => {
if (!list || !list.result) {
return;
}
list = list.result;
fillSelect('#serialport', list);
$('#serialport.value').val(settings.serialport).select();
});
}
/**
* Load all devices, make the list global as array (only name) and object (name & id).
*/
function getDeviceList(){
sendTo(null, 'getDevices', null, (list) => {
deviceList = list;
//mfrArray.push(keys[i].replace(/_/g, ' '));
mfrArray = Object.keys(list);
mfrArray.sort();
})
}
/**
* Load all EEP, make the list global as array (only name) and object (complete profile).
*/
function getEEPList(){
sendTo(null, 'getEEPList', null, (list) => {
eepList = list;
for(let i in eepList){
eepArray.push(eepList[i].eep);
}
})
}
function fillEEPselect(){
if(eepListFilled === false){
fillSelect('#select-eep', eepArray);
eepListFilled = true;
$('#select-eep')
.select()
.change((option) => {
let eep = option.target.value.replace(/-/g, '');
$('#device-name').val(eepList[eep].type_title);
});
}
}
function fillMfrselect(){
if(mfrListFilled === false){
fillSelect('#select-manufacturer', mfrArray);
mfrListFilled = true;
$('#select-manufacturer').select();
}
}
function fillDeviceSelect(){
fillSelect('#select-device', deviceArray)
$('#select-device').select();
}
/**
* List all known devices on devices tab.
* @param {object} obj - ioBroker object for the device
*/
function showDevice(obj) {
let text = '';
text += '<td >' + obj.native.id + '</td>';
if(obj.native.Sender_ID) {
text += '<td >' + obj.native.Sender_ID + '</td>';
} else {
text += '<td>' + '--' + '</td>';
}
text += '<td>' + obj.native.eep + '</td>';
if(obj.native.manufacturer) {
text += '<td>' + obj.native.manufacturer + '</td>';
} else {
text += '<td>' + '--' + '</td>';
}
if (obj.common.name) {
text += '<td>' + obj.common.name + '</td>';
} else {
text += '<td>' + '--' + '</td>';
}
text += '<td>' + '' +
'<a id="'+ obj.native.id + obj.common.role + '" class="delete-device values-buttons btn-floating btn-small waves-effect waves-light red"><i class="material-icons" title="Delete device">delete</i></a>';
for (let i in deviceCommands) {
text += '<option value="' + i + '">' + _(i) + '</option>';
}
text += '</select></td>';
text = '<tr data-id="' + obj.native.id + '">' + text + '</tr>';
$('#devices_body').append(text);
$('#' + obj.native.id + obj.common.role).click(function(e){
sendTo('enocean.' + instance, 'deleteDevice', obj.native.id);
// remove from list
$(this).closest('tr').remove();
});
}
function getDevices() {
socket.emit('getObjectView', 'system', 'device', { startkey: 'enocean.' + instance + '.', endkey: 'enocean.' + instance + '.\u9999', include_docs: true }, function (err, _devices) {
socket.emit('getStates', function (err, _values) {
let namespace = 'enocean.' + instance + '.';
$('#devices_body').html('');
if (_devices && _devices.rows && _devices.rows.length) {
for (let j = 0; j < _devices.rows.length; j++) {
devices[_devices.rows[j].value._id] = _devices.rows[j].value;
if(_devices.rows[j].value._id !== namespace + 'gateway'){
showDevice(_devices.rows[j].value);
}
}
}
});
});
}
function loadSysConfig(){
socket.emit('getObject', 'system.config', function (err, res) {
sysConfig = res;
});
}
function getGateway() {
socket.emit('getObject', 'enocean.' + instance + '.gateway', function (err, res) {
$('#BaseID').text(res.native.BaseID);
});
}
function getSystemInformation() {
sendTo(null, 'getSystemInfo', null, (info) => {
$('#systemInfo').text('``` \n' + JSON.stringify(info, undefined, 2) + '\n```');
});
}
// Copy to clipboard
function copyToClipboard(element) {
navigator.clipboard.writeText(element);
}
//subscribe to lastID
socket.emit('subscribe', 'enocean.' + instance + '.gateway.lastID');
socket.on('stateChange', function (id, state) {
//console.log(state);
if(id === 'enocean.' + instance + '.gateway.lastID'){
$('#lastID').text(state.val);
}
});
/**
* Load the adapter config page.
* @param {object} settings - The adapter settings
* @param onChange - call this if there are settings changed that should be saved (will activate the save buttons)
*/
function load(settings, onChange) {
loadSysConfig();
$('.modal').modal();
let selectorInputs = document.querySelectorAll('select');
instances = M.FormSelect.init(selectorInputs);
if (settings.ser2net === false){
$('#ser2net-div').removeClass('hide');
$('#options-serialport-div').removeClass('hide');
} else {
$('#ser2net-div').removeClass('hide');
$('#options-ser2net-ip-div').removeClass('hide');
$('#options-ser2net-port-div').removeClass('hide');
$('#ser2net-ip').val(settings['ser2net-ip']);
$('#ser2net-port').val(settings['ser2net-port']);
}
$('#gateway')
.val(settings.gateway)
.on('change', () => {
let $gateway = $('#gateway').val();
if( $gateway === 'usb300' || $gateway === 'fgw14-usb'){
$('#ser2net-div').removeClass('hide');
if(settings.ser2net === false){
$('#options-serialport-div').removeClass('hide');
$('#options-ser2net-ip-div').addClass('hide');
$('#options-ser2net-port-div').addClass('hide');
} else {
$('#options-serialport-div').addClass('hide');
$('#options-ser2net-ip-div').removeClass('hide');
$('#options-ser2net-port-div').removeClass('hide');
$('#ser2net-ip').val(settings['ser2net-ip']);
$('#ser2net-port').val(settings['ser2net-port']);
}
}
if( $gateway === 'all-smart'|| $gateway === 'bsc-multigateway'){
$('#options-ser2net-ip-div').removeClass('hide');
$('#options-ser2net-port-div').removeClass('hide');
$('#ser2net-div').addClass('hide');
$('#options-serialport-div').addClass('hide');
}
onChange();
})
// example: select elements with id=key and class=value and insert value
if (!settings) return;
$('.value').each(function () {
let $key = $(this);
let 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', () => onChange());
} else if($key.attr('class') === 'save'){
// do not call onChange direct, because onChange could expect some arguments
$key.val(settings[id])
.on('change', () => onChange())
.on('keyup', () => onChange());
}
});
showdown.setFlavor('github');
$('#ser2net').on('change', () => {
if( $('#ser2net').prop('checked') === true ){
$('#options-serialport-div').addClass('hide');
$('#options-ser2net-ip-div').removeClass('hide');
$('#options-ser2net-port-div').removeClass('hide');
} else {
$('#options-serialport-div').removeClass('hide');
$('#options-ser2net-ip-div').addClass('hide');
$('#options-ser2net-port-div').addClass('hide');
}
setTimeout(function(){
onChange();
}, 100);
})
$('#serialport').on('change', () => {
onChange();
})
getComPorts(settings);
//getmfrList();
getDeviceList();
getEEPList();
$('#addDevice').on('click', () => {
fillEEPselect();
fillMfrselect();
$('#select-eep').on('change', () => {
M.updateTextFields();
})
});
//fill devices by manufacturer
$('#select-manufacturer').on('change', () => {
let selected = $('#select-manufacturer').val();
deviceArray = Object.keys(deviceList[selected])
fillDeviceSelect();
})
//show additional fields for selected device
$('#select-device').on('change', ()=>{
$('#help')
.empty()
.removeClass('hide');
const mfr = $('#select-manufacturer').val();
const dev = $('#select-device').val();
if(deviceList[mfr][dev].autocreate === false){
$('#div-id').removeClass('hide');
} else {
$('#div-id').addClass('hide');
}
const device = deviceList[mfr][dev].help[sysConfig.common.language];
for (let i in device) {
let card = '<div class="col s12">\n' +
'\t\t\t\t\t\t<div class="card light-blue lighten-4">\n' +
'\t\t\t\t\t\t\t<div class="card-content black-text">\n' +
'\t\t\t\t\t\t\t\t<span class="card-title">\n' +
'\t\t\t\t\t\t\t\t<div class="col s2 translate">Step</div>\n' +
'\t\t\t\t\t\t\t\t<div class="col s10 translate">' + i + '</div></span>\n' +
'\t\t\t\t\t\t\t\t<p>' + device[i] + '</p>\n' +
'\t\t\t\t\t\t\t</div>\n' +
'\t\t\t\t\t\t</div>\n' +
'\t\t\t\t\t</div>\n';
$('#help').append(card);
}
translateAll();
})
// Initialize copy-support-info button
$('#copy-support-info').on('click', () => {
let text = $('#systemInfo').text();
copyToClipboard(text);
});
$('#addDeviceSubmit').on('click', () => {
const manufacturer = $('#select-manufacturer').val();
const device = $('#select-device').val();
const name = device;
if (deviceList[manufacturer][device].autocreate === false) {
const deviceId = $('#device-id').val();
sendTo(null, 'newDevice', {device: name, mfr: manufacturer, id: deviceId}, (data) => {
if (data.result === 'Ready') {
getDevices();
}
});
} else {
sendTo(null, 'autodetect', {teachin_method: deviceList[manufacturer][device].teachin_method, device: name, mfr: manufacturer}, () => {
setInterval( () => {
getDevices();
}, 1000)
})
}
});
//make a device request
/*$('#requestDeviceSubmit').on('click', () => {
//window.open('https://github.com/Jey-Cee/ioBroker.enocean/issues?q=label%3A%22Device+request%22+');
deviceRequest($('#manufacturer').val(), $('#model').val(), $('#prod-date').val(), $('#link').val(), $('#additional').val());
})*/
// populate the list of known devices
getDevices();
getGateway();
getSystemInformation();
onChange(false);
// reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
if (M) M.updateTextFields();
$('#additional').keyup(() => {
M.textareaAutoResize($('#additional'));
})
}
// 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
let obj = {};
$('.value').each(function () {
let $this = $(this);
if ($this.attr('type') === 'checkbox') {
console.log($this.attr('id'));
console.log($this.prop('checked'));
obj[$this.attr('id')] = $this.prop('checked');
} else {
obj[$this.attr('id')] = $this.val();
}
});
callback(obj);
}
</script>
</head>
<body>
<div class="m adapter-container">
<!-- Navbar -->
<div class="row">
<div class="col s12">
<ul class="tabs">
<li class="tab col s2"><a href="#tab-devices" class="translate active">Devices</a></li>
<li class="tab col s2"><a href="#tab-main" class="translate active">Settings</a></li>
<li class="tab col s2"><a href="#tab-support-info" class="translate active">Support information</a></li>
</ul>
</div>
<!-- Options Tab -->
<div id="tab-main" class="col s12 page" style="height: 100%">
<div class="row">
<div class="col s12 m4 l2">
<img src="enocean.png" class="logo" style="height:7em; width: 7em;" alt="EnOcean">
</div>
</div>
<div class="row">
<div id="options-Gateway" class="input-field col s12 m6 l3">
<select id="gateway" class="value save" >
<option value="">Select Gateway</option>
<option value="usb300">USB300</option>
<option value="usb300">EnOcean Pi</option>
<option value="usb300">FAM-USB (ESP3 Firmware)</option>
<option value="fgw14-usb">FGW14(-USB)</option>
<option value="all-smart">ALL SMART EnOcean LAN Gateway</option>
<option value="bsc-multigateway">BSC EnOcean Multigateway</option>
</select>
<label for="gateway" class="translate">Gateway</label>
</div>
</div>
<div class="row">
<div id="ser2net-div" class="switch col s4 input-field hide" style="z-index: 10">
<label>
USB/Serial
<input id="ser2net" type="checkbox" class="value save">
<span class="lever"></span>
Serial over network (Ser2Net)
</label>
</div>
<div id="important" class="col s12 m12 l12">
<p class="translate">IMPORTANT: Use save button NOT save and close</p>
</div>
<div id="options-serialport-div" class="input-field col s12 m6 l3 hide">
<select id="serialport" class="value save" ></select>
<label for="serialport" class="translate">Serial port</label>
</div>
<div id="options-ser2net-ip-div" class="input-field col s12 m6 l3 hide">
<input class="text value save" id="ser2net-ip" size="15" type="text">
<label class="translate active" for="ser2net-ip">IP</label>
</div>
<div id="options-ser2net-port-div" class="input-field col s12 m6 l3 hide">
<input class="text value save" id="ser2net-port" size="6" type="number">
<label class="translate active" for="ser2net-port">Port</label>
</div>
<div class="col s1">
<!-- spacer -->
</div>
<div class="switch col s4 input-field hide">
<label>
Editor
<input id="options-switch-editor" type="checkbox">
<span class="lever"></span>
Attention: Use it at your own risk.
</label>
</div>
</div>
</div>
<!-- Devices Tab -->
<div id="tab-devices" class="col s12 page">
<div class="row">
<div class="input-field col">
<a id="addDevice" class="waves-effect waves-light btn modal-trigger translate" href="#add-device">Add new device</a>
</div>
<div class="col s2 push-s8">
<div class="card blue lighten-3">
<div class="card-content center-align" style="font-size: 1.3em;">
<span class="translate">Base ID: </span><span id="BaseID">ffffff</span>
</div>
</div>
</div>
</div>
<div id="devices">
<table class="centered">
<thead>
<tr>
<th class="translate">ID</th>
<th class="translate">Sender ID</th>
<th class="translate">EEP</th>
<th class="translate" data-lang="manufacturer">Manufacturer</th>
<th class="translate" data-lang="device">Device</th>
<th class="translate" ></th>
</tr>
</thead>
<tbody id="devices_body" class="table-values">
</tbody>
</table>
</div>
</div>
<!-- Support information Tab -->
<div id="tab-support-info" class="col s12 page">
<div class="row">
<div id="info-body" class="col s12">
<!-- Show support information as code with copy to clipboard button -->
<div class="card">
<div class="card-content">
<span class="card-title translate">Support information</span>
<pre id="systemInfo" class="support-info"></pre>
</div>
<div class="card-action">
<a id="copy-support-info" class="waves-effect waves-light btn translate" href="#">Copy to clipboard</a>
</div>
</div>
</div>
</div>
</div>
<!-- Add Device Modal Structure -->
<div id="add-device" class="modal modal-fixed-footer">
<div class="modal-content">
<h5 class="translate center">Add new device</h5>
<div class="row">
<div class="input-field col s5">
<select id="select-manufacturer">
<option value="" class="translate" disabled selected>Choose</option>
</select>
<label class="translate" for="select-manufacturer">manufacturer</label>
</div>
<div class="input-field col s5">
<select id="select-device">
<option value="" class="translate" disabled selected>Choose</option>
</select>
<label class="translate" for="select-device">device</label>
</div>
<div
id="div-id" class="input-field col s2 hide">
<input id="device-id" class="value" type="text" placeholder="e.g. 0014A42D" minlength="8" maxlength="8">
<label for="device-id" class="translate">Device ID</label>
</div>
<div class="input-field col s12 hide">
<input id="device-name" class="value" type="text">
<label for="device-name" class="translate">Device Name</label>
</div>
<div class="input-field col s3 hide">
<select id="select-eep">
<option value="" class="translate" disabled selected>Choose</option>
</select>
<label for="select-eep">EEP</label>
</div>
</div>
<div id="help" class="row hide">
</div>
</div>
<div class="row">
<div class="col s3 push-s9">
<div class="card blue lighten-3">
<div class="card-content center-align" style="padding:7px;">
<span class="translate">Last seen ID: </span><span id="lastID" style="font-size: 1.3em;">ffffff</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="col" style="position:absolute; left: 15px;" >
<a id="requestDevice" class="waves-effect waves-light btn modal-close modal-trigger translate" href="#request-device">Device not listed?</a>
</div>
<button id="addDeviceSubmit" class="btn waves-effect waves-light modal-close modal-action translate" type="submit" name="action">Add device</button>
<button class="btn waves-effect waves-light modal-close modal-action translate" href="#!">Close</button>
</div>
</div>
<!-- Request device -->
<div id="request-device" class="modal modal-fixed-footer">
<div class="modal-content">
<h5 class="translate center">Request device integration</h5>
<div class="row">
<p class="translate">Request Device Text</p>
</div>
</div>
<div class="modal-footer">
<a href="https://github.com/Jey-Cee/ioBroker.enocean/issues/new?assignees=Jey-Cee&labels=Device+request&template=device-request.md&title=" target=”_blank”><button id="requestDeviceSubmit" class="btn waves-effect waves-light modal-close modal-action translate" type="submit" name="action">Send request</button></a>
<button class="btn waves-effect waves-light modal-close modal-action translate" href="#!">Close</button>
</div>
</div>
</div>
</body>
</html>