mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2025-12-13 11:02:12 +01:00
Change pairing so that the command can be repeated on failure. #15. Add extra 0 to indicate there are no more bits to be read from the bitstream.
This commit is contained in:
parent
3b8c2e0aea
commit
b6bc57e437
8 changed files with 119 additions and 20 deletions
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
Preferences pref;
|
Preferences pref;
|
||||||
bool BaseSettings::load() { return true; }
|
bool BaseSettings::load() { return true; }
|
||||||
bool BaseSettings::save() { return true; }
|
|
||||||
bool BaseSettings::loadFile(const char *filename) {
|
bool BaseSettings::loadFile(const char *filename) {
|
||||||
size_t filesize = 10;
|
size_t filesize = 10;
|
||||||
String data = "";
|
String data = "";
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ class NTPSettings: BaseSettings {
|
||||||
class WifiSettings: BaseSettings {
|
class WifiSettings: BaseSettings {
|
||||||
public:
|
public:
|
||||||
WifiSettings();
|
WifiSettings();
|
||||||
// char hostname[32] = "ESPSomfyRTS";
|
|
||||||
char ssid[64] = "";
|
char ssid[64] = "";
|
||||||
char passphrase[64] = "";
|
char passphrase[64] = "";
|
||||||
//bool ssdpBroadcast = true;
|
//bool ssdpBroadcast = true;
|
||||||
|
|
|
||||||
15
Somfy.cpp
15
Somfy.cpp
|
|
@ -1455,6 +1455,7 @@ void SomfyRemote::sendCommand(somfy_commands cmd, uint8_t repeat) {
|
||||||
frame.cmd = cmd;
|
frame.cmd = cmd;
|
||||||
frame.repeats = repeat;
|
frame.repeats = repeat;
|
||||||
frame.bitLength = this->bitLength;
|
frame.bitLength = this->bitLength;
|
||||||
|
// Match the encKey to the rolling code. These keys range from 160 to 175.
|
||||||
frame.encKey = 0xA0 | static_cast<uint8_t>(frame.rollingCode & 0x000F);
|
frame.encKey = 0xA0 | static_cast<uint8_t>(frame.rollingCode & 0x000F);
|
||||||
if(frame.bitLength == 0) frame.bitLength = bit_length;
|
if(frame.bitLength == 0) frame.bitLength = bit_length;
|
||||||
this->lastRollingCode = frame.rollingCode;
|
this->lastRollingCode = frame.rollingCode;
|
||||||
|
|
@ -1684,11 +1685,16 @@ void Transceiver::sendFrame(byte *frame, uint8_t sync, uint8_t bitLength) {
|
||||||
delayMicroseconds(SYMBOL);
|
delayMicroseconds(SYMBOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// End with a 0 no matter what. This accommodates the 56-bit protocol by telling the
|
||||||
|
// motor that there are no more follow on bits.
|
||||||
|
REG_WRITE(GPIO_OUT_W1TS_REG, pin);
|
||||||
|
//delayMicroseconds(SYMBOL/2);
|
||||||
|
|
||||||
// Inter-frame silence for 56-bit protocols are around 34ms. However, an 80 bit protocol should
|
// Inter-frame silence for 56-bit protocols are around 34ms. However, an 80 bit protocol should
|
||||||
// reduce this by the transmission of SYMBOL * 24 or 15,360us
|
// reduce this by the transmission of SYMBOL * 24 or 15,360us
|
||||||
REG_WRITE(GPIO_OUT_W1TC_REG, pin);
|
REG_WRITE(GPIO_OUT_W1TC_REG, pin);
|
||||||
// Below are the original calculations for inter-frame silence. However, when actually inspecting this from
|
// Below are the original calculations for inter-frame silence. However, when actually inspecting this from
|
||||||
// the remote it appears to be closer to 27500us. The delayMicoseconds call is also cannot be called with
|
// the remote it appears to be closer to 27500us. The delayMicoseconds call cannot be called with
|
||||||
// values larger than 16383.
|
// values larger than 16383.
|
||||||
/*
|
/*
|
||||||
if(bitLength == 80)
|
if(bitLength == 80)
|
||||||
|
|
@ -1696,9 +1702,10 @@ void Transceiver::sendFrame(byte *frame, uint8_t sync, uint8_t bitLength) {
|
||||||
else
|
else
|
||||||
delayMicroseconds(30415);
|
delayMicroseconds(30415);
|
||||||
*/
|
*/
|
||||||
delayMicroseconds(13750);
|
if(bitLength != 80) {
|
||||||
if(bitLength != 80) // Part of the inter-frame silence is used to transport data.
|
|
||||||
delayMicroseconds(13750);
|
delayMicroseconds(13750);
|
||||||
|
delayMicroseconds(13750);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RECEIVE_ATTR Transceiver::handleReceive() {
|
void RECEIVE_ATTR Transceiver::handleReceive() {
|
||||||
|
|
@ -1749,7 +1756,7 @@ void RECEIVE_ATTR Transceiver::handleReceive() {
|
||||||
somfy_rx.cpt_bits = 0;
|
somfy_rx.cpt_bits = 0;
|
||||||
somfy_rx.bit_length = 56;
|
somfy_rx.bit_length = 56;
|
||||||
}
|
}
|
||||||
else if((somfy_rx.pulseCount > 10 && somfy_rx.cpt_synchro_hw == 0) || duration > 150000) {
|
else if((somfy_rx.pulseCount > 20 && somfy_rx.cpt_synchro_hw == 0) || duration > 250000) {
|
||||||
somfy_rx.pulseCount = 0;
|
somfy_rx.pulseCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
8
Utils.h
8
Utils.h
|
|
@ -51,7 +51,13 @@ typedef struct rebootDelay_t {
|
||||||
int rebootTime = 0;
|
int rebootTime = 0;
|
||||||
bool closed = false;
|
bool closed = false;
|
||||||
};
|
};
|
||||||
|
static bool toBoolean(const char *str, bool def) {
|
||||||
|
if(!str) return def;
|
||||||
|
if(strlen(str) == 0) return def;
|
||||||
|
else if(str[0] == 't' || str[0] == 'T' || str[0] == '1') return true;
|
||||||
|
else if(str[0] == 'f' || str[0] == 'F' || str[0] == '0') return false;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
class Timestamp {
|
class Timestamp {
|
||||||
char _timeBuffer[44];
|
char _timeBuffer[44];
|
||||||
|
|
|
||||||
51
Web.cpp
51
Web.cpp
|
|
@ -170,7 +170,7 @@ void Web::begin() {
|
||||||
shade->moveToTarget(target);
|
shade->moveToTarget(target);
|
||||||
else
|
else
|
||||||
shade->sendCommand(command, repeat);
|
shade->sendCommand(command, repeat);
|
||||||
DynamicJsonDocument sdoc(256);
|
DynamicJsonDocument sdoc(512);
|
||||||
JsonObject sobj = sdoc.to<JsonObject>();
|
JsonObject sobj = sdoc.to<JsonObject>();
|
||||||
shade->toJSON(sobj);
|
shade->toJSON(sobj);
|
||||||
serializeJson(sdoc, g_content);
|
serializeJson(sdoc, g_content);
|
||||||
|
|
@ -234,7 +234,7 @@ void Web::begin() {
|
||||||
shade->moveToTiltTarget(target);
|
shade->moveToTiltTarget(target);
|
||||||
else
|
else
|
||||||
shade->sendTiltCommand(command);
|
shade->sendTiltCommand(command);
|
||||||
DynamicJsonDocument sdoc(256);
|
DynamicJsonDocument sdoc(512);
|
||||||
JsonObject sobj = sdoc.to<JsonObject>();
|
JsonObject sobj = sdoc.to<JsonObject>();
|
||||||
shade->toJSON(sobj);
|
shade->toJSON(sobj);
|
||||||
serializeJson(sdoc, g_content);
|
serializeJson(sdoc, g_content);
|
||||||
|
|
@ -870,6 +870,52 @@ void Web::begin() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
server.on("/setPaired", []() {
|
||||||
|
webServer.sendCORSHeaders();
|
||||||
|
uint8_t shadeId = 255;
|
||||||
|
bool paired = false;
|
||||||
|
if(server.hasArg("plain")) {
|
||||||
|
DynamicJsonDocument doc(512);
|
||||||
|
DeserializationError err = deserializeJson(doc, server.arg("plain"));
|
||||||
|
if(err) {
|
||||||
|
switch(err.code()) {
|
||||||
|
case DeserializationError::InvalidInput:
|
||||||
|
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Invalid JSON payload\"}"));
|
||||||
|
break;
|
||||||
|
case DeserializationError::NoMemory:
|
||||||
|
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Out of memory parsing JSON\"}"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"General JSON Deserialization failed\"}"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JsonObject obj = doc.as<JsonObject>();
|
||||||
|
if (obj.containsKey("shadeId")) shadeId = obj["shadeId"];
|
||||||
|
if(obj.containsKey("paired")) paired = obj["paired"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (server.hasArg("shadeId"))
|
||||||
|
shadeId = atoi(server.arg("shadeId").c_str());
|
||||||
|
if(server.hasArg("paired"))
|
||||||
|
paired = toBoolean(server.arg("paired").c_str(), false);
|
||||||
|
SomfyShade* shade = nullptr;
|
||||||
|
if (shadeId != 255) shade = somfy.getShadeById(shadeId);
|
||||||
|
if (!shade) {
|
||||||
|
server.send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade not found to pair\"}"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shade->paired = paired;
|
||||||
|
shade->save();
|
||||||
|
DynamicJsonDocument doc(512);
|
||||||
|
JsonObject obj = doc.to<JsonObject>();
|
||||||
|
shade->toJSON(obj);
|
||||||
|
serializeJson(doc, g_content);
|
||||||
|
server.send(200, _encoding_json, g_content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/*
|
||||||
server.on("/pairShade", []() {
|
server.on("/pairShade", []() {
|
||||||
webServer.sendCORSHeaders();
|
webServer.sendCORSHeaders();
|
||||||
HTTPMethod method = server.method();
|
HTTPMethod method = server.method();
|
||||||
|
|
@ -919,6 +965,7 @@ void Web::begin() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
server.on("/unpairShade", []() {
|
server.on("/unpairShade", []() {
|
||||||
webServer.sendCORSHeaders();
|
webServer.sendCORSHeaders();
|
||||||
HTTPMethod method = server.method();
|
HTTPMethod method = server.method();
|
||||||
|
|
|
||||||
|
|
@ -1696,6 +1696,42 @@ class Somfy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setPaired(shadeId, paired) {
|
||||||
|
let obj = { shadeId: shadeId, paired: paired || false };
|
||||||
|
let div = document.getElementById('divPairing');
|
||||||
|
let overlay = typeof div === 'undefined' ? undefined : waitMessage(div);
|
||||||
|
putJSON('/setPaired', obj, (err, shade) => {
|
||||||
|
if (overlay) overlay.remove();
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
errorMessage(div, err.message);
|
||||||
|
}
|
||||||
|
else if (div) {
|
||||||
|
console.log(shade);
|
||||||
|
document.getElementById('somfyMain').style.display = 'none';
|
||||||
|
document.getElementById('somfyShade').style.display = '';
|
||||||
|
document.getElementById('btnSaveShade').style.display = 'inline-block';
|
||||||
|
document.getElementById('btnLinkRemote').style.display = '';
|
||||||
|
document.getElementsByName('shadeAddress')[0].value = shade.remoteAddress;
|
||||||
|
document.getElementsByName('shadeName')[0].value = shade.name;
|
||||||
|
document.getElementsByName('shadeUpTime')[0].value = shade.upTime;
|
||||||
|
document.getElementsByName('shadeDownTime')[0].value = shade.downTime;
|
||||||
|
let ico = document.getElementById('icoShade');
|
||||||
|
ico.style.setProperty('--shade-position', `${shade.position}%`);
|
||||||
|
ico.setAttribute('data-shadeid', shade.shadeId);
|
||||||
|
if (shade.paired) {
|
||||||
|
document.getElementById('btnUnpairShade').style.display = 'inline-block';
|
||||||
|
document.getElementById('btnPairShade').style.display = 'none';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.getElementById('btnPairShade').style.display = 'inline-block';
|
||||||
|
document.getElementById('btnUnpairShade').style.display = 'none';
|
||||||
|
}
|
||||||
|
this.setLinkedRemotesList(shade);
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
pairShade(shadeId) {
|
pairShade(shadeId) {
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
let html = `<div id="divPairing" class="instructions" data-type="link-remote" data-shadeid="${shadeId}">`;
|
let html = `<div id="divPairing" class="instructions" data-type="link-remote" data-shadeid="${shadeId}">`;
|
||||||
|
|
@ -1706,10 +1742,12 @@ class Somfy {
|
||||||
html += '<li>Press the prog button on the back of the remote until the shade jogs</li>';
|
html += '<li>Press the prog button on the back of the remote until the shade jogs</li>';
|
||||||
html += '<li>After the shade jogs press the Prog button below</li>';
|
html += '<li>After the shade jogs press the Prog button below</li>';
|
||||||
html += '<li>The shade should jog again indicating that the shade is paired</li>';
|
html += '<li>The shade should jog again indicating that the shade is paired</li>';
|
||||||
html += '<li>You may now press the close button</li>'
|
html += '<li>If the shade jogs, you can press the shade paired button.</li>'
|
||||||
|
html += '<li>If the shade does not jog, press the prog button again.</li>'
|
||||||
html += '</ul>'
|
html += '</ul>'
|
||||||
html += `<div class="button-container">`
|
html += `<div class="button-container">`
|
||||||
html += `<button id="btnSendPairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.sendPairCommand(${shadeId});">Prog</button>`
|
html += `<button id="btnSendPairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.sendCommand(${shadeId}, 'prog', 1);">Prog</button>`
|
||||||
|
html += `<button id="btnMarkPaired" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.setPaired(${shadeId}, true);">Shade Paired</button>`
|
||||||
html += `<button id="btnStopPairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block" onclick="document.getElementById('divPairing').remove();">Close</button>`
|
html += `<button id="btnStopPairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block" onclick="document.getElementById('divPairing').remove();">Close</button>`
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
|
|
@ -1726,24 +1764,27 @@ class Somfy {
|
||||||
html += '<li>Press the prog button on the back of the remote until the shade jogs</li>';
|
html += '<li>Press the prog button on the back of the remote until the shade jogs</li>';
|
||||||
html += '<li>After the shade jogs press the Prog button below</li>';
|
html += '<li>After the shade jogs press the Prog button below</li>';
|
||||||
html += '<li>The shade should jog again indicating that the shade is unpaired</li>';
|
html += '<li>The shade should jog again indicating that the shade is unpaired</li>';
|
||||||
html += '<li>You may now press the close button</li>'
|
html += '<li>If the shade jogs, you can press the shade unpaired button.</li>'
|
||||||
|
html += '<li>If the shade does not jog, press the prog button again until the shade jogs.</li>'
|
||||||
html += '</ul>'
|
html += '</ul>'
|
||||||
html += `<div class="button-container">`
|
html += `<div class="button-container">`
|
||||||
html += `<button id="btnSendUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.sendUnpairCommand(${shadeId});">Prog</button>`
|
html += `<button id="btnSendUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.sendCommand(${shadeId}, 'prog', 1);">Prog</button>`
|
||||||
|
html += `<button id="btnMarkPaired" type="button" style="padding-left:20px;padding-right:20px;display:inline-block;" onclick="somfy.setPaired(${shadeId}, false);">Shade Unpaired</button>`
|
||||||
html += `<button id="btnStopUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block" onclick="document.getElementById('divPairing').remove();">Close</button>`
|
html += `<button id="btnStopUnpairing" type="button" style="padding-left:20px;padding-right:20px;display:inline-block" onclick="document.getElementById('divPairing').remove();">Close</button>`
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
document.getElementById('somfyShade').appendChild(div);
|
document.getElementById('somfyShade').appendChild(div);
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
sendCommand(shadeId, command) {
|
sendCommand(shadeId, command, repeat) {
|
||||||
console.log(`Sending Shade command ${shadeId}-${command}`);
|
console.log(`Sending Shade command ${shadeId}-${command}`);
|
||||||
if (isNaN(parseInt(command, 10)))
|
let obj = { shadeId: shadeId };
|
||||||
putJSON('/shadeCommand', { shadeId: shadeId, command: command }, (err, shade) => {
|
if (isNaN(parseInt(command, 10))) obj.command = command;
|
||||||
});
|
else obj.target = parseInt(command, 10);
|
||||||
else
|
if (typeof repeat === 'number') obj.repeat = parseInt(repeat);
|
||||||
putJSON('/shadeCommand', { shadeId: shadeId, target: parseInt(command, 10) }, (err, shade) => {
|
putJSON('/shadeCommand', obj, (err, shade) => {
|
||||||
});
|
|
||||||
|
});
|
||||||
};
|
};
|
||||||
sendTiltCommand(shadeId, command) {
|
sendTiltCommand(shadeId, command) {
|
||||||
console.log(`Sending Tilt command ${shadeId}-${command}`);
|
console.log(`Sending Tilt command ${shadeId}-${command}`);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue