iobroker.esphome
Version:
Control your ESP8266/ESP32 with simple yet powerful configuration files created and managed by ESPHome
434 lines (379 loc) • 18.2 kB
HTML
<html>
<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>
<!-- 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">
let _onChange;
// Create secret for encrypted password storage
let secret;
function encryptManuell(key, value) {
var result = '';
for(var i = 0; i < value.length; ++i) {
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
}
return result;
}
function decryptManuell(key, value) {
var result = '';
for (var i = 0; i < value.length; ++i) {
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
}
return result;
}
// Build table based on devices known in instance
function loadTable(obj) {
let index = 0;
let text = '';
console.log('Data for table ' + JSON.stringify(obj)); //device-pass
for (i in obj) {
if (obj[i] !== undefined) {
text += '<tr id="' + obj[i].value.native.deviceName + '"><td><span id="' + obj[i].value.native.deviceName + '-index">' + obj[i].value.native.deviceName + '</span></td>';
text += '<td> <input id="' + index + '-Name" type="text" disabled="true" class="center-align input-field" value=' + obj[i].value.common.name + '></td>';
text += '<td> <input id="' + index + '-ip" type="text" disabled class="center-align input-field" value="' + obj[i].value.native.ip + '"></td>';
text += '<td> <div class="led-all center-led led-gray"></div></td>';
text += `<td>
<a class="btn-floating btn-small waves-effect waves-light modal-trigger blue" onclick='editIPAddress(${index})' data-target="modal-edit-device"><i class="material-icons">create</i></a>
<a onclick="delete_device('${obj[i].value.native.deviceName}')" class="delete-table-row btn-floating btn-small waves-effect waves-light red"><i class="material-icons">delete</i></a>
</td>`;
text += '</tr>';
index = (index + 1);
}
}
$('#devices').append(text);
$('.delete-table-row').on('click', (event) => {
console.log('delete');
$(event.currentTarget).parentsUntil('tr').parent().remove();
});
getConnectedState();
$('input, .delete-device').each(function () {
let $key = $(this);
$key.on('click', function () {
_onChange();
}).keyup(function () {
_onChange();
});
$key.change(function () {
_onChange();
}).keyup(function () {
_onChange();
});
});
}
function editIPAddress(index) {
// let deviceObj
socket.emit('getObjectView', 'system', 'device', {startkey: 'esphome.' + instance + '.', endkey: 'esphome.' + instance + '.\u9999', include_docs: true}, function (err, _devices) {
console.log('Return of all devices : ' + JSON.stringify(_devices));
let text = '';
text += `
<p class="translate">You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)</p>
<p class="translate">When Encryption Key is provided, API-Password will be ignored</p>
<div class="input-field ip col s8">
<label for="device-ip"></label><input placeholder="192.168.0.100" class="center" id="device-ip" type="text"/>
<span class="translate">IP</span>
</div>
<div class="input-field pass col s8">
<label for="deviceEncryptionKey"></label><input class="center" id="deviceEncryptionKey" type="password"/>
<span class="translate">deviceEncryptionKey</span>
</div>
<div class="input-field pass col s8">
<label for="device-pass"></label><input class="center" id="device-pass" type="password"/>
<span class="translate">device-pass</span>
</div>`;
$(`#edit_device_container`).html(text);
});
}
function delete_device(device_id) {
console.log('test' + device_id);
sendTo(null, 'removeDevice', device_id, (data) => {
});
}
// Get value of connection state
function getConnectedState() {
socket.emit('getObjectView', 'system', 'device', {startkey: 'esphome.' + instance + '.', endkey: 'esphome.' + instance + '.\u9999', include_docs: true}, function (err, _devices) {
let namespace = 'esphome.' + instance + '.';
let len = namespace.length;
console.log('Return of all devices : ' + JSON.stringify(_devices));
if (_devices && _devices.rows && _devices.rows.length) {
for (const i in _devices.rows) {
getState(_devices.rows[i].id + '.info._online', (err, state) => {
console.log(JSON.stringify('Connection value for device : ' + _devices.rows[i].id + ' value ' + state.val));
let connectState = null;
if (state.val === true) {
connectState = 'led-green';
}
else {
connectState = 'led-red';
}
console.log(connectState);
let tableRow = $('td').filter((index, e) => {
console.log(e);
return $(e).text() === _devices.rows[i].value.native.deviceName;
}).closest('tr');
console.log($(tableRow).attr('id'));
$('#' + $(tableRow).attr('id') + '> td > .led-all').removeClass('led-gray');
$('#' + $(tableRow).attr('id') + '> td > .led-all').addClass(connectState);
});
}
}
});
}
// This will be called by the admin adapter when the settings page loads
function loadHelper(settings, onChange) {
_onChange = 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 (id === 'apiPass') {
settings[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 {
// do not call onChange direct, because onChange could expect some arguments
$key.val(settings[id])
.on('change', () => onChange())
.on('keyup', () => onChange());
}
});
onChange(false);
// reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
M.updateTextFields();
}
function load(settings, onChange) {
// example: select elements with id=key and class=value and insert value
if (!settings) return;
socket.emit('getObject', 'system.config', function (err, obj) {
secret = (obj.native ? obj.native.secret : '') || 'Zgfr56gFe87jJOM';
loadHelper(settings, onChange);
});
// initialize modal
$('.modal').modal();
emitDevices();
$('#btn-edit-device').on('click', () => {
console.log('Add device button executed');
messageObj = {
'device-ip': $('#device-ip').val(),
'device-pass': encryptManuell(secret, $('#device-pass').val()),
'deviceEncryptionKey': encryptManuell(secret, $('#deviceEncryptionKey').val())
};
sendTo(null, 'addDevice', messageObj, (data) => {
console.log('Message from backend : ' + data);
if (data.message === 'success') {
$('#devices > tr').remove();
emitDevices();
}
else {
errorFunction(data);
}
});
});
$('#btn-add-device').on('click', () => {
console.log('Add device button executed');
messageObj = {
'device-ip': $('#device-ip').val(),
// 'device-pass': decryptManuell(secret, $('#device-pass').val())
'device-pass': encryptManuell(secret, $('#device-pass').val()),
'deviceEncryptionKey': encryptManuell(secret, $('#deviceEncryptionKey').val())
};
sendTo(null, 'addDevice', messageObj, (data) => {
console.log('Message from backend : ' + data);
if (data.message === 'success') {
$('#devices > tr').remove();
emitDevices();
}
else {
errorFunction(data);
}
});
});
onChange(false);
// reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
if (M) M.updateTextFields();
}
function errorFunction(data) {
let text = '';
text += `
<h5 class="center ${data.type}">${data.type}</h5>
<div class="row col s12 center">
<p class="break-word" >${data.message}</p>
</div>
<div class="row"></div>`;
$(`#error_container`).html(text);
$('#modal-error-message').modal('open');
}
// This will be called by the admin adapter when the user presses the save button
function save(callback) {
let obj = {};
$('.value').each(function () {
var $this = $(this);
var id = $this.attr('id');
if ($this.attr('type') === 'checkbox') {
obj[id] = $this.prop('checked');
}
else {
obj[id] = $this.val();
}
});
callback(obj);
console.log('test');
}
// Read all devices from instance
function emitDevices() {
socket.emit('getObjectView', 'system', 'device', {startkey: 'esphome.' + instance + '.', endkey: 'esphome.' + instance + '.\u9999', include_docs: true}, function (err, _devices) {
let namespace = 'esphome.' + instance + '.';
let len = namespace.length;
console.log('Return of all devices : ' + JSON.stringify(_devices));
if (_devices && _devices.rows && _devices.rows.length) {
console.log('Loopje : ' + len);
loadTable(_devices.rows);
}
});
}
</script>
</head>
<body>
<div class="m adapter-container">
<div class="row">
<div class="col s12 m4 l2">
<img src="esphome.png" class="logo" alt='esphome'>
</div>
</div>
<div class="section">
<p class="translate title">ESPHome Dashboard integration</p>
<div class="row">
<div class="input-field col s4">
<input type="checkbox" class="value" id="ESPHomeDashboardEnabled" />
<span class="translate">ESPHomeDashboardEnabled</span>
</div>
<div class="col s3 input-field">
<input type="text" class="value" id="ESPHomeDashboardIP" />
<label for="ESPHomeDashboardIP" class="translate">ESPHomeDashboardIP</label>
</div>
<div class="col s2 input-field">
<input type="text" class="value" disabled="true" id="ESPHomeDashboardPort" />
<label for="ESPHomeDashboardPort" class="translate">ESPHomeDashboardPort</label>
</div>
</div>
<div class="row center">
<p class="translate">ESPHome_Dashboard_Generic_info</p>
<p class="translate">ESPHome_Dashboard_IP_info</p>
</div>
<p class="translate title">Devices can be added manually or by autodiscovery</p>
<!-- <h6 class="translate">Devices can be added manually or by autodiscovery</h6>-->
<div class="row">
<div class="input-field">
<a id="add-device" class="table-button-add col s2 waves-effect waves-light btn btn-large blue modal-trigger translate" data-target="modal-add-device"><i class="large left material-icons">add_circle</i>Add Device</a>
</div>
<!-- reconnect interval -->
<div class="col s2 input_field input-field">
<label for="reconnectInterval"></label><input type="number" class="value center" id="reconnectInterval" max="3600" min="20" value="30"/>
<span class="translate">reconnect interval</span>
</div>
<!-- end reconnect interval -->
<!-- default Password -->
<div class="col s2 input_field input-field">
<label for="apiPass"></label><input type="password" class="value" id="apiPass" value=""/>
<span class="translate">API password</span>
</div>
<!-- end default Password -->
<!-- Auto Discovery -->
<div class="col s4 input-field">
<label for="autodiscovery"></label><input type="checkbox" class="value" id="autodiscovery" checked/>
<span class="translate">Automatic device detection activated</span>
</div>
<!-- end Auto Discovery -->
<div class="col s4 input-field">
<label for="autodiscovery"></label><input type="checkbox" class="value" id="configStates" checked/>
<span class="translate">Show configuration as states</span>
</div>
</div>
<!-- <p class="translate title">Devices</p>-->
<div class="col s10 m10 l10 xl10 row">
<div class="table-values-div">
<table class="table-values centered">
<thead>
<tr>
<th class="translate">ID</th>
<th class="translate">Name</th>
<th class="translate">IP-Address</th>
<th class="translate">Connected</th>
<th class="translate">Delete</th>
</tr>
</thead>
<tbody id="devices"></tbody>
</table>
</div>
</div>
<!-- Modal for edit input -->
<div id="modal-edit-device" class="modal">
<div class="modal-content">
<h5 class="translate center">Edit device</h5>
<div id='edit_device_container' class="row center">
<!--contend-->
</div>
</div>
<div class="modal-footer">
<button id="btn-edit-device" class="btn waves-effect waves-light modal-close modal-action translate">Edit</button>
<button class="btn waves-effect waves-light modal-close modal-action translate">Close</button>
</div>
</div>
<!-- END for Modal for edit input -->
<!-- Modal for manual ip input -->
<div id="modal-add-device" class="modal">
<div class="modal-content">
<h5 class="translate center">Add device manually</h5>
<div class="row center">
<p class="translate">You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)</p>
<p class="translate">When Encryption Key is provided, API-Password will be ignored</p>
<div class="input-field ip col s8">
<label for="device-ip"></label><input placeholder="192.168.0.100" class="center" id="device-ip" type="text"/>
<span class="translate">IP</span>
</div>
<div class="input-field pass col s8">
<label for="deviceEncryptionKey"></label><input class="center" id="deviceEncryptionKey" type="password"/>
<span class="translate">deviceEncryptionKey</span>
</div>
<div class="input-field pass col s8">
<label for="device-pass"></label><input class="center" id="device-pass" type="password"/>
<span class="translate">device-pass</span>
</div>
</div>
</div>
<div class="modal-footer">
<button id="btn-add-device" class="btn waves-effect waves-light modal-close modal-action translate">Add</button>
<button class="btn waves-effect waves-light modal-close modal-action translate">Close</button>
</div>
</div>
<!-- END for Modal for manual ip input -->
<!-- Modal for error message -->
<div id="modal-error-message" class="modal">
<div class="content">
<div id='error_container'>
<!--content-->
</div>
</div>
<div class="row">
<div class="center">
<button class="btn waves-effect center waves-light modal-close modal-action translate">Close</button>
</div>
</div>
</div>
<!-- END for Modal for error message -->
</div>
</div>
</body>
</html>