Fix toggle button for 1-button controllers.

This commit is contained in:
Robert Strouse 2023-09-19 20:54:24 -07:00
parent 5598790310
commit ea37fa0002
6 changed files with 219 additions and 15 deletions

107
Somfy.cpp
View file

@ -347,6 +347,7 @@ void somfy_frame_t::encodeFrame(byte *frame) {
frame[9] = 25;
break;
case somfy_commands::Prog:
//frame[0] = 0xA6;
frame[7] = 196;
frame[8] = 0;
frame[9] = 25;
@ -1637,13 +1638,23 @@ void SomfyShade::processFrame(somfy_frame_t &frame, bool internal) {
}
break;
case somfy_commands::My:
if(this->shadeType == shade_types::drycontact) {
if(this->shadeType == shade_types::garage1) {
if(this->lastFrame.processed) return;
this->lastFrame.processed = true;
if(!this->isIdle()) this->target = this->currentPos;
else if(this->currentPos == 100.0f) this->target = 0;
else if(this->currentPos == 0.0f) this->target = 100;
else this->target = this->lastMovement == -1 ? 100 : 0;
return;
}
else if(this->shadeType == shade_types::drycontact) {
// In this case we need to toggle the contact but we only should do this if
// this is not a repeat.
if(this->lastFrame.processed) return;
this->lastFrame.processed = true;
this->target = this->currentPos = this->currentPos > 0 ? 0 : 100;
this->emitState();
if(this->currentPos == 100.0f) this->target = 0;
else if(this->currentPos == 0.0f) this->target = 100;
else this->target = this->lastMovement == -1 ? 100 : 0;
return;
}
if(this->isIdle()) {
@ -2030,7 +2041,9 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat) {
if(this->tiltType == tilt_types::integrated) this->tiltTarget = 100.0f;
}
else if(cmd == somfy_commands::My) {
if(this->isIdle()) {
if(this->shadeType == shade_types::garage1 || this->shadeType == shade_types::drycontact)
SomfyRemote::sendCommand(cmd, repeat);
else if(this->isIdle()) {
this->moveToMyPosition();
return;
}
@ -2040,6 +2053,10 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat) {
this->tiltTarget = this->currentTiltPos;
}
}
else if(cmd == somfy_commands::Toggle) {
if(this->bitLength != 80) SomfyRemote::sendCommand(somfy_commands::My, repeat);
else SomfyRemote::sendCommand(somfy_commands::Toggle, repeat);
}
else if(this->shadeType == shade_types::garage1 && cmd == somfy_commands::Prog) {
SomfyRemote::sendCommand(somfy_commands::Toggle, repeat);
}
@ -3114,6 +3131,69 @@ void RECEIVE_ATTR Transceiver::handleReceive() {
somfy_rx.status = waiting_synchro;
}
}
float currFreq = 433.0f;
int currRSSI = -100;
float markFreq = 433.0f;
int markRSSI = -100;
uint32_t lastScan = 0;
void Transceiver::beginFrequencyScan() {
if(this->config.enabled) {
this->disableReceive();
rxmode = 3;
pinMode(this->config.RXPin, INPUT);
interruptPin = digitalPinToInterrupt(this->config.RXPin);
ELECHOUSE_cc1101.setRxBW(this->config.rxBandwidth); // Set the Receive Bandwidth in kHz. Value from 58.03 to 812.50. Default is 812.50 kHz.
ELECHOUSE_cc1101.SetRx();
markFreq = currFreq = 433.0f;
markRSSI = -100;
ELECHOUSE_cc1101.setMHZ(currFreq);
Serial.printf("Begin frequency scan on Pin #%d\n", this->config.RXPin);
attachInterrupt(interruptPin, handleReceive, CHANGE);
this->emitFrequencyScan();
}
}
void Transceiver::processFrequencyScan(bool received) {
if(this->config.enabled && rxmode == 3) {
if(received) {
currRSSI = ELECHOUSE_cc1101.getRssi();
if((long)(markFreq * 100) == (long)(currFreq * 100)) {
markRSSI = currRSSI;
}
else if(currRSSI >-75) {
if(currRSSI > markRSSI) {
markRSSI = currRSSI;
markFreq = currFreq;
}
}
}
else {
currRSSI = -100;
}
if(millis() - lastScan > 100 && somfy_rx.status == waiting_synchro) {
lastScan = millis();
this->emitFrequencyScan();
currFreq += 0.01f;
if(currFreq > 434.0f) currFreq = 433.0f;
ELECHOUSE_cc1101.setMHZ(currFreq);
}
}
}
void Transceiver::endFrequencyScan() {
if(rxmode == 3) {
rxmode = 0;
if(interruptPin > 0) detachInterrupt(interruptPin);
interruptPin = 0;
this->config.apply();
this->emitFrequencyScan();
}
}
void Transceiver::emitFrequencyScan(uint8_t num) {
char buf[420];
snprintf(buf, sizeof(buf), "{\"scanning\":%s,\"testFreq\":%f,\"testRSSI\":%d,\"frequency\":%f,\"RSSI\":%d}", rxmode == 3 ? "true" : "false", currFreq, currRSSI, markFreq, markRSSI);
if(num >= 255) sockEmit.sendToClients("frequencyScan", buf);
else sockEmit.sendToClient(num, "frequencyScan", buf);
}
bool Transceiver::receive() {
// Check to see if there is anything in the buffer
if(rx_queue.length > 0) {
@ -3123,7 +3203,6 @@ bool Transceiver::receive() {
this->frame.decodeFrame(&rx);
this->emitFrame(&this->frame, &rx);
return this->frame.valid;
}
return false;
}
@ -3494,14 +3573,22 @@ bool Transceiver::begin() {
return true;
}
void Transceiver::loop() {
if (this->receive()) {
//this->clearReceived();
if(rxmode == 3) {
if(rx_queue.length > 0) {
//Serial.printf("Processing receive %d\n", rx_queue.length);
somfy_rx_t rx;
rx_queue.pop(&rx);
this->frame.decodeFrame(&rx);
this->processFrequencyScan(this->frame.valid);
}
else
this->processFrequencyScan(false);
}
else if (this->receive())
somfy.processFrame(this->frame, false);
}
else {
else
somfy.processWaitingFrame();
}
}
somfy_frame_t& Transceiver::lastFrame() { return this->frame; }
void Transceiver::beginTransmit() {
if(this->config.enabled) {

View file

@ -413,6 +413,10 @@ class Transceiver {
void beginTransmit();
void endTransmit();
void emitFrame(somfy_frame_t *frame, somfy_rx_t *rx = nullptr);
void beginFrequencyScan();
void endFrequencyScan();
void processFrequencyScan(bool received = false);
void emitFrequencyScan(uint8_t num = 255);
};
class SomfyShadeController {
protected:

Binary file not shown.

19
Web.cpp
View file

@ -2180,6 +2180,25 @@ void Web::begin() {
}
}
});
server.on("/beginFrequencyScan", []() {
webServer.sendCORSHeaders(server);
somfy.transceiver.beginFrequencyScan();
DynamicJsonDocument doc(1024);
JsonObject obj = doc.to<JsonObject>();
somfy.transceiver.toJSON(obj);
serializeJson(doc, g_content);
server.send(200, _encoding_json, g_content);
});
server.on("/endFrequencyScan", []() {
webServer.sendCORSHeaders(server);
somfy.transceiver.endFrequencyScan();
DynamicJsonDocument doc(1024);
JsonObject obj = doc.to<JsonObject>();
somfy.transceiver.toJSON(obj);
serializeJson(doc, g_content);
server.send(200, _encoding_json, g_content);
});
server.begin();
apiServer.begin();
}

View file

@ -388,13 +388,13 @@
<label for="cbHasLight" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Has Light</label>
</div>
</div>
<div style="margin-top:-10px;">
<div style="margin-top:-10px;" id="divFlipCommands">
<div class="field-group" style="display:inline-block">
<input id="cbFlipCommands" name="flipCommands" data-bind="flipCommands" type="checkbox" style="" />
<label for="cbFlipCommands" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Invert Commands</label>
</div>
</div>
<div style="margin-top:-10px;">
<div style="margin-top:-10px;" id="divFlipPosition">
<div class="field-group">
<input id="cbFlipPosition" name="flipPos" data-bind="flipPosition" type="checkbox" style="" />
<label for="cbFlipPosition" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;display:inline-block;">Invert Position (expressed in % of open)</label>
@ -666,7 +666,7 @@
</div>
<div class="field-group" style="display:inline-block;width:auto;min-width:247px;margin-top:-20px;vertical-align:top;">
<div class="field-group">
<input id="slidFrequency" name="frequency" type="range" min="433330" max="434399" step="1" style="width:100%;" data-bind="transceiver.config.frequency" data-datatype="float" data-mult="1000" oninput="somfy.frequencyChanged(this);" />
<input id="slidFrequency" name="frequency" type="range" min="433000" max="434399" step="1" style="width:100%;" data-bind="transceiver.config.frequency" data-datatype="float" data-mult="1000" oninput="somfy.frequencyChanged(this);" />
<label for="slidFrequency" style="display:block;font-size:1em;margin-top:0px;margin-left:7px;">
<span>Base Frequency </span>
<span style="float:right;display:inline-block;margin-right:7px;">
@ -703,6 +703,10 @@
<button id="btnSaveRadio" type="button" onclick="somfy.saveRadio();">
Save Radio
</button>
<button id="btnScanFrequency" type="button" onclick="somfy.scanFrequency(true);">
Scan Frequency
</button>
</div>
</div>
<div id="divFrameLog" class="subtab-content frame-log" style="display:none;margin:0px;padding:0px;">

View file

@ -489,6 +489,9 @@ async function initSockets() {
case 'packetPulses':
console.log(msg);
break;
case 'frequencyScan':
somfy.procFrequencyScan(msg);
break;
}
} catch (err) {
@ -1929,6 +1932,86 @@ class Somfy {
}
}
}
procFrequencyScan(scan) {
//console.log(scan);
let div = this.scanFrequency();
let spanTestFreq = document.getElementById('spanTestFreq');
let spanTestRSSI = document.getElementById('spanTestRSSI');
let spanBestFreq = document.getElementById('spanBestFreq');
let spanBestRSSI = document.getElementById('spanBestRSSI');
if (spanBestFreq) {
spanBestFreq.innerHTML = scan.RSSI !== -100 ? scan.frequency.fmt('###.00') : '----';
}
if (spanBestRSSI) {
spanBestRSSI.innerHTML = scan.RSSI !== -100 ? scan.RSSI : '----';
}
if (spanTestFreq) {
spanTestFreq.innerHTML = scan.testFreq.fmt('###.00');
}
if (spanTestRSSI) {
spanTestRSSI.innerHTML = scan.testRSSI !== -100 ? scan.testRSSI : '----';
}
if (scan.RSSI !== -100)
div.setAttribute('data-frequency', scan.frequency);
}
scanFrequency(initScan) {
let div = document.getElementById('divScanFrequency');
if (!div || typeof div === 'undefined') {
div = document.createElement('div');
div.setAttribute('id', 'divScanFrequency');
div.classList.add('prompt-message');
let html = '<div class="sub-message">Frequency Scanning has started. Press and hold any button on your remote and ESPSomfy RTS will find the closest frequency to the remote.</div>';
html += '<hr style="width:100%;margin:0px;"></hr>';
html += '<div class="" style="font-size:20px;"><label style="padding-right:7px;display:inline-block;width:87px;">Scanning</label><span id="spanTestFreq" style="display:inline-block;width:4em;text-align:right;">433.00</span><span>MHz</span><label style="padding-left:12px;padding-right:7px;">RSSI</label><span id="spanTestRSSI">----</span><span>dBm</span></div>';
html += '<div class="" style="font-size:20px;"><label style="padding-right:7px;display:inline-block;width:87px;">Frequency</label><span id="spanBestFreq" style="display:inline-block;width:4em;text-align:right;">---.--</span><span>MHz</span><label style="padding-left:12px;padding-right:7px;">RSSI</label><span id="spanBestRSSI">----</span><span>dBm</span></div>';
html += `<div class="button-container">`;
html += `<button id="btnStopScanning" type="button" style="padding-left:20px;padding-right:20px;" onclick="somfy.stopScanningFrequency(true);">Stop Scanning</button>`;
html += `<button id="btnRestartScanning" type="button" style="padding-left:20px;padding-right:20px;display:none;" onclick="somfy.scanFrequency(true);">Start Scanning</button>`;
html += `<button id="btnCopyFrequency" type="button" style="padding-left:20px;padding-right:20px;display:none;" onclick="somfy.setScannedFrequency();">Set Frequency</button>`;
html += `<button id="btnCloseScanning" type="button" style="padding-left:20px;padding-right:20px;width:100%;display:none;" onclick="document.getElementById('divScanFrequency').remove();">Close</button>`;
html += `</div>`;
div.innerHTML = html;
document.getElementById('divRadioSettings').appendChild(div);
}
if (initScan) {
div.setAttribute('data-initscan', true);
putJSONSync('/beginFrequencyScan', {}, (err, trans) => {
if (!err) {
document.getElementById('btnStopScanning').style.display = '';
document.getElementById('btnRestartScanning').style.display = 'none';
document.getElementById('btnCopyFrequency').style.display = 'none';
document.getElementById('btnCloseScanning').style.display = 'none';
}
});
}
return div;
}
setScannedFrequency() {
let div = document.getElementById('divScanFrequency');
let freq = parseFloat(div.getAttribute('data-frequency'));
let slid = document.getElementById('slidFrequency');
slid.value = Math.round(freq * 1000);
somfy.frequencyChanged(slid);
div.remove();
}
stopScanningFrequency(killScan) {
let div = document.getElementById('divScanFrequency');
if (div && killScan !== true) {
div.remove();
}
else {
putJSONSync('/endFrequencyScan', {}, (err, trans) => {
if (err) ui.serviceError(err);
else {
let freq = parseFloat(div.getAttribute('data-frequency'));
document.getElementById('btnStopScanning').style.display = 'none';
document.getElementById('btnRestartScanning').style.display = '';
if(typeof freq === 'number') document.getElementById('btnCopyFrequency').style.display = '';
document.getElementById('btnCloseScanning').style.display = '';
}
});
}
}
btnDown = null;
btnTimer = null;
// Sort the array first to allow the user to drag and drop where they want the shade.
@ -2585,6 +2668,8 @@ class Somfy {
let sun = true;
let light = false;
let lift = true;
let flipCommands = true;
let flipPosition = true;
let ico = document.getElementById('icoShade');
let type = parseInt(sel.value, 10);
document.getElementById('somfyShade').setAttribute('data-shadetype', type);
@ -2641,8 +2726,9 @@ class Somfy {
if (ico.classList.contains('icss-lightbulb')) ico.classList.remove('icss-lightbulb');
tilt = false;
break;
case 6:
case 5:
flipCommands = false;
case 6:
document.getElementById('divTiltSettings').style.display = 'none';
if (ico.classList.contains('icss-window-shade')) ico.classList.remove('icss-window-shade');
if (ico.classList.contains('icss-ldrapery')) ico.classList.remove('icss-ldrapery');
@ -2698,6 +2784,8 @@ class Somfy {
tilt = false;
light = false;
sun = false;
flipPosition = false;
flipCommands = false;
break;
@ -2720,6 +2808,8 @@ class Somfy {
document.querySelector('#divSomfyButtons i.icss-window-tilt').style.display = tilt ? '' : 'none';
document.getElementById('divSunSensor').style.display = sun ? '' : 'none';
document.getElementById('divLightSwitch').style.display = light ? '' : 'none';
document.getElementById('divFlipPosition').style.display = flipPosition ? '' : 'none';
document.getElementById('divFlipCommands').style.display = flipCommands ? '' : 'none';
if (!light) document.getElementById('cbHasLight').checked = false;
if (!sun) document.getElementById('cbHasSunsensor').checked = false;
}