';
document.getElementById('btnScanAPs').classList.add('disabled');
//document.getElementById('btnConnectWiFi').classList.add('disabled');
getJSON('/scanaps', (err, aps) => {
document.getElementById('btnScanAPs').classList.remove('disabled');
//document.getElementById('btnConnectWiFi').classList.remove('disabled');
console.log(aps);
if (err) {
this.displayAPs({ connected: { name: '', passphrase: '' }, accessPoints: [] });
}
else {
this.displayAPs(aps);
}
});
};
displayAPs(aps) {
let div = '';
let nets = [];
for (let i = 0; i < aps.accessPoints.length; i++) {
let ap = aps.accessPoints[i];
let p = nets.find(elem => elem.name === ap.name);
if (typeof p !== 'undefined' && p) {
p.channel = p.strength > ap.strength ? p.channel : ap.channel;
p.macAddress = p.strength > ap.strength ? p.macAddress : ap.macAddress;
p.strength = Math.max(p.strength, ap.strength);
}
else
nets.push(ap);
}
// Sort by the best signal strength.
nets.sort((a, b) => b.strength - a.strength);
for (let i = 0; i < nets.length; i++) {
let ap = nets[i];
div += `
${ap.name}${this.displaySignal(ap.strength)}
`;
}
let divAps = document.getElementById('divAps');
divAps.setAttribute('data-lastloaded', new Date().getTime());
divAps.innerHTML = div;
//document.getElementsByName('ssid')[0].value = aps.connected.name;
//document.getElementsByName('passphrase')[0].value = aps.connected.passphrase;
//this.procWifiStrength(aps.connected);
};
selectSSID(el) {
let obj = {
name: el.querySelector('span.ssid').innerHTML,
encryption: el.getAttribute('data-encryption'),
strength: parseInt(el.getAttribute('data-strength'), 10),
channel: parseInt(el.getAttribute('data-channel'), 10)
}
console.log(obj);
document.getElementsByName('ssid')[0].value = obj.name;
};
calcWaveStrength(sig) {
let wave = 0;
if (sig > -90) wave++;
if (sig > -80) wave++;
if (sig > -70) wave++;
if (sig > -67) wave++;
if (sig > -30) wave++;
return wave;
};
displaySignal(sig) {
return `
`;
};
saveNetwork() {
let obj = {
connType: document.getElementById('cbHardwired').checked ? document.getElementById('cbFallbackWireless').checked ? 3 : 2 : 1,
wifi: {},
ethernet: {}
};
if (obj.connType >= 2) {
// We are connecting to a LAN but we need the user to be sure about this since
// the information needs to be correct. Incorrect settings can destroy the board.
obj.ethernet = {
boardType: parseInt(document.getElementById('selETHBoardType').value, 10),
phyType: parseInt(document.getElementById('selETHPhyType').value, 10),
phyAddress: parseInt(document.getElementById('selETHAddress').value, 10),
dhcp: document.getElementById('cbUseDHCP').checked,
CLKMode: parseInt(document.getElementById('selETHClkMode').value, 10),
PWRPin: parseInt(document.getElementById('selETHPWRPin').value, 10),
MDCPin: parseInt(document.getElementById('selETHMDCPin').value, 10),
MDIOPin: parseInt(document.getElementById('selETHMDIOPin').value, 10),
ip: document.getElementById('fldIPAddress').value,
subnet: document.getElementById('fldSubnetMask').value,
gateway: document.getElementById('fldGateway').value,
dns1: document.getElementById('fldDNS1').value,
dns2: document.getElementById('fldDNS2').value
}
let boardType = this.ethBoardTypes.find(elem => obj.ethernet.boardType === elem.val);
let phyType = this.ethPhyTypes.find(elem => obj.ethernet.phyType === elem.val);
let clkMode = this.ethClockModes.find(elem => obj.ethernet.CLKMode === elem.val);
let div = document.createElement('div');
let html = `
`;
html += '
BEWARE ... WARNING ... DANGER
';
html += '';
html += '
If this shade is already paired with a motor then changing the rolling code WILL cause it to stop working. Rolling codes are tied to the remote address and the Somfy motor expects these to be sequential.
';
html += '
If you hesitated just a little bit do not press the red button. Green represents safety so press it, wipe the sweat from your brow, and go through the normal pairing process.'
html += '
';
html += ``;
html += '';
html += '
'
html += `
`
html += ``
html += ``
html += `
`;
div.innerHTML = html;
document.getElementById('somfyShade').appendChild(div);
}
});
}
pairShade(shadeId) {
let div = document.createElement('div');
let html = `
`;
html += '
Follow the instructions below to pair this shade with a Somfy motor
'
html += '';
html += '
';
html += '
Open the shade memory using an existing remote
';
html += '
Press the prog button on the back of the remote until the shade jogs
';
html += '
After the shade jogs press the Prog button below
';
html += '
The shade should jog again indicating that the shade is paired
';
html += '
You may now press the close button
'
html += '
'
html += `
`
html += ``
html += ``
html += `
`;
div.innerHTML = html;
document.getElementById('somfyShade').appendChild(div);
return div;
};
unpairShade(shadeId) {
let div = document.createElement('div');
let html = `
`;
html += '
Follow the instructions below to unpair this shade from a Somfy motor
'
html += '';
html += '
';
html += '
Open the shade memory using an existing remote
';
html += '
Press the prog button on the back of the remote until the shade jogs
';
html += '
After the shade jogs press the Prog button below
';
html += '
The shade should jog again indicating that the shade is unpaired
';
html += '
You may now press the close button
'
html += '
'
html += `
`
html += ``
html += ``
html += `
`;
div.innerHTML = html;
document.getElementById('somfyShade').appendChild(div);
return div;
};
sendCommand(shadeId, command) {
let data = { shadeId: shadeId };
if (isNaN(parseInt(command, 10)))
putJSON('/shadeCommand', { shadeId: shadeId, command: command }, (err, shade) => {
});
else
putJSON('/shadeCommand', { shadeId: shadeId, target: parseInt(command, 10) }, (err, shade) => {
});
};
linkRemote(shadeId) {
let div = document.createElement('div');
let html = `
`;
html += '
Press any button on the remote to link it to this shade. This will not change the pairing for the remote and this screen will close when the remote is detected.
';
html += '';
html += `
`;
html += '
';
div.innerHTML = html;
document.getElementById('somfyShade').appendChild(div);
return div;
};
unlinkRemote(shadeId, remoteAddress) {
let prompt = promptMessage(document.getElementById('fsSomfySettings'), 'Are you sure you want to unlink this remote from the shade?', () => {
let obj = {
shadeId: shadeId,
remoteAddress: remoteAddress
};
let overlay = waitMessage(prompt);
putJSON('/unlinkRemote', obj, (err, shade) => {
console.log(shade);
overlay.remove();
prompt.remove();
this.setLinkedRemotesList(shade);
});
});
};
deviationChanged(el) {
document.getElementById('spanDeviation').innerText = (el.value / 100).fmt('#,##0.00');
};
rxBandwidthChanged(el) {
document.getElementById('spanRxBandwidth').innerText = (el.value / 100).fmt('#,##0.00');
};
txPowerChanged(el) {
console.log(el.value);
let lvls = [-30, -20, -15, -10, -6, 0, 5, 7, 10, 11, 12];
document.getElementById('spanTxPower').innerText = lvls[el.value];
};
processShadeTarget(el, shadeId) {
let positioner = document.querySelector(`.shade-positioner[data-shadeid="${shadeId}"]`);
if (positioner) {
positioner.querySelector(`.shade-target`).innerHTML = el.value;
somfy.sendCommand(shadeId, el.value);
}
}
openSetPosition(shadeId) {
console.log('Opening Shade Positioner');
if (typeof shadeId === 'undefined') {
return;
}
else {
let shade = document.querySelector(`div.somfyShadeCtl[data-shadeid="${shadeId}"]`);
if (shade) {
let ctls = document.querySelectorAll('.shade-positioner');
for (let i = 0; i < ctls.length; i++) {
console.log('Closing shade positioner');
ctls[i].remove();
}
let currPos = parseInt(shade.getAttribute('data-target'), 0);
let elname = shade.querySelector(`.shadectl-name`);
let shadeName = elname.innerHTML;
let html = `
${shadeName}
`;
html += ``;
html += ``;
html += `
`;
let div = document.createElement('div');
div.setAttribute('class', 'shade-positioner');
div.setAttribute('data-shadeid', shadeId);
div.addEventListener('onclick', (event) => { event.stopPropagation(); });
div.innerHTML = html;
shade.appendChild(div);
document.body.addEventListener('click', () => {
let ctls = document.querySelectorAll('.shade-positioner');
for (let i = 0; i < ctls.length; i++) {
console.log('Closing shade positioner');
ctls[i].remove();
}
}, { once: true });
}
}
}
};
var somfy = new Somfy();
class MQTT {
async init() { this.loadMQTT(); }
async loadMQTT() {
let overlay = waitMessage(document.getElementById('fsMQTTSettings'));
getJSON('/mqttsettings', (err, settings) => {
overlay.remove();
if (err) {
console.log(err);
}
else {
console.log(settings);
let dd = document.getElementsByName('mqtt-protocol')[0];
for (let i = 0; i < dd.options.length; i++) {
if (dd.options[i].text === settings.proto) {
dd.selectedIndex = i;
break;
}
}
if (dd.selectedIndex < 0) dd.selectedIndex = 0;
document.getElementsByName('mqtt-host')[0].value = settings.hostname;
document.getElementsByName('mqtt-port')[0].value = settings.port;
document.getElementsByName('mqtt-username')[0].value = settings.username;
document.getElementsByName('mqtt-password')[0].value = settings.password;
document.getElementsByName('mqtt-topic')[0].value = settings.rootTopic;
document.getElementsByName('mqtt-enabled')[0].checked = settings.enabled;
}
});
};
connectMQTT() {
if (document.getElementById('btnConnectMQTT').classList.contains('disabled')) return;
document.getElementById('btnConnectMQTT').classList.add('disabled');
let obj = {
enabled: document.getElementsByName('mqtt-enabled')[0].checked,
protocol: document.getElementsByName('mqtt-protocol')[0].value,
hostname: document.getElementsByName('mqtt-host')[0].value,
port: parseInt(document.getElementsByName('mqtt-port')[0].value, 10),
username: document.getElementsByName('mqtt-username')[0].value,
password: document.getElementsByName('mqtt-password')[0].value,
rootTopic: document.getElementsByName('mqtt-topic')[0].value
}
console.log(obj);
if (isNaN(obj.port) || obj.port < 0) {
errorMessage(document.getElementById('fsMQTTSettings'), 'Invalid port number. Likely ports are 1183, 8883 for MQTT/S or 80,443 for HTTP/S');
return;
}
let overlay = waitMessage(document.getElementById('fsMQTTSettings'));
putJSON('/connectmqtt', obj, (err, response) => {
overlay.remove();
document.getElementById('btnConnectMQTT').classList.remove('disabled');
console.log(response);
});
};
};
var mqtt = new MQTT();
class Firmware {
async init() { }
createFileUploader(service) {
let div = document.createElement('div');
div.setAttribute('id', 'divUploadFile');
div.setAttribute('class', 'instructions');
div.style.width = '100%';
let html = `
`;
html += ``;
html += ``;
html += ``;
html += ``
html += `
`
html += ``
html += `
`;
html += `
`;
div.innerHTML = html;
return div;
};
updateFirmware() {
let div = this.createFileUploader('/updateFirmware');
let inst = div.querySelector('div[id=divInstText]');
inst.innerHTML = '
Select a binary file containing the device firmware then press the Upload File button.
';
document.getElementById('fsUpdates').appendChild(div);
};
updateApplication() {
let div = this.createFileUploader('/updateApplication');
general.reloadApp = true;
let inst = div.querySelector('div[id=divInstText]');
inst.innerHTML = '
Select a binary file containing the littlefs data for the application then press the Upload File button.
';
document.getElementById('fsUpdates').appendChild(div);
};
async uploadFile(service, el) {
let field = el.querySelector('input[type="file"]');
let filename = field.value;
console.log(filename);
switch (service) {
case '/updateApplication':
if (filename.indexOf('.littlefs') === -1 || !filename.endsWith('.bin')) {
errorMessage(el, 'This file is not a valid littleFS file system.');
return;
}
break;
case '/updateFirmware':
if (filename.indexOf('.ino.') === -1 || !filename.endsWith('.bin')) {
errorMessage(el, 'This file is not a valid firmware binary file.');
return;
}
break;
}
let formData = new FormData();
let btnUpload = el.querySelector('button[id="btnUploadFile"]');
let btnCancel = el.querySelector('button[id="btnClose"]');
btnUpload.style.display = 'none';
field.disabled = true;
let btnSelectFile = el.querySelector('div[id="btn-select-file"]');
let prog = el.querySelector('div[id="progFileUpload"]');
prog.style.display = '';
btnSelectFile.style.visibility = 'hidden';
formData.append('file', field.files[0]);
let xhr = new XMLHttpRequest();
xhr.open('POST', service, true);
xhr.upload.onprogress = function (evt) {
let pct = evt.total ? Math.round((evt.loaded / evt.total) * 100) : 0;
prog.style.setProperty('--progress', `${pct}%`);
prog.setAttribute('data-progress', `${pct}%`);
console.log(evt);
};
xhr.onload = function () {
console.log('File upload load called');
btnCancel.innerText = 'Close';
};
xhr.send(formData);
};
};
var firmware = new Firmware();