mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-03-30 08:52:11 +02:00
fix race condition with multiple simultaneus requests
This commit is contained in:
parent
2e379e6c1e
commit
d5b8acecda
4 changed files with 203 additions and 21 deletions
|
|
@ -101,8 +101,10 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
|
||||||
if (shade) {
|
if (shade) {
|
||||||
int val = atoi(value);
|
int val = atoi(value);
|
||||||
if(strncmp(command, "target", sizeof(command)) == 0) {
|
if(strncmp(command, "target", sizeof(command)) == 0) {
|
||||||
if(val >= 0 && val <= 100)
|
if(val >= 0 && val <= 100) {
|
||||||
|
ESP_LOGI(TAG, "MQTT shade %s target=%d", entityId, val);
|
||||||
shade->moveToTarget(shade->transformPosition(atoi(value)));
|
shade->moveToTarget(shade->transformPosition(atoi(value)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(strncmp(command, "tiltTarget", sizeof(command)) == 0) {
|
if(strncmp(command, "tiltTarget", sizeof(command)) == 0) {
|
||||||
if(val >= 0 && val <= 100)
|
if(val >= 0 && val <= 100)
|
||||||
|
|
@ -152,6 +154,7 @@ void MQTTClass::receive(const char *topic, byte*payload, uint32_t length) {
|
||||||
SomfyGroup* group = somfy.getGroupById(atoi(entityId));
|
SomfyGroup* group = somfy.getGroupById(atoi(entityId));
|
||||||
if (group) {
|
if (group) {
|
||||||
int val = atoi(value);
|
int val = atoi(value);
|
||||||
|
ESP_LOGI(TAG, "MQTT group %s command=%s value=%d", entityId, command, val);
|
||||||
if(strncmp(command, "direction", sizeof(command)) == 0) {
|
if(strncmp(command, "direction", sizeof(command)) == 0) {
|
||||||
if(val < 0)
|
if(val < 0)
|
||||||
group->sendCommand(somfy_commands::Up);
|
group->sendCommand(somfy_commands::Up);
|
||||||
|
|
|
||||||
|
|
@ -2926,11 +2926,12 @@ void SomfyShade::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
||||||
}
|
}
|
||||||
void SomfyGroup::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
|
void SomfyGroup::sendCommand(somfy_commands cmd) { this->sendCommand(cmd, this->repeats); }
|
||||||
void SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
void SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize) {
|
||||||
|
ESP_LOGI(TAG, "[Group %u] sendCommand cmd=%s repeat=%u", this->getGroupId(), translateSomfyCommand(cmd).c_str(), repeat);
|
||||||
// This sendCommand function will always be called externally. sendCommand at the remote level
|
// This sendCommand function will always be called externally. sendCommand at the remote level
|
||||||
// is expected to be called internally when the motor needs commanded.
|
// is expected to be called internally when the motor needs commanded.
|
||||||
if(this->bitLength == 0) this->bitLength = somfy.transceiver.config.type;
|
if(this->bitLength == 0) this->bitLength = somfy.transceiver.config.type;
|
||||||
SomfyRemote::sendCommand(cmd, repeat, stepSize);
|
SomfyRemote::sendCommand(cmd, repeat, stepSize);
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case somfy_commands::My:
|
case somfy_commands::My:
|
||||||
this->p_direction(0);
|
this->p_direction(0);
|
||||||
|
|
@ -2949,6 +2950,7 @@ void SomfyGroup::sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSiz
|
||||||
if(this->linkedShades[i] != 0) {
|
if(this->linkedShades[i] != 0) {
|
||||||
SomfyShade *shade = somfy.getShadeById(this->linkedShades[i]);
|
SomfyShade *shade = somfy.getShadeById(this->linkedShades[i]);
|
||||||
if(shade) {
|
if(shade) {
|
||||||
|
ESP_LOGI(TAG, "[Group %u] processInternalCommand on shade %u cmd=%s", this->getGroupId(), shade->getShadeId(), translateSomfyCommand(cmd).c_str());
|
||||||
shade->processInternalCommand(cmd, repeat);
|
shade->processInternalCommand(cmd, repeat);
|
||||||
shade->emitCommand(cmd, "group", this->getRemoteAddress());
|
shade->emitCommand(cmd, "group", this->getRemoteAddress());
|
||||||
}
|
}
|
||||||
|
|
@ -2994,6 +2996,8 @@ void SomfyShade::moveToTiltTarget(float target) {
|
||||||
if(cmd != somfy_commands::My) this->settingTiltPos = true;
|
if(cmd != somfy_commands::My) this->settingTiltPos = true;
|
||||||
}
|
}
|
||||||
void SomfyShade::moveToTarget(float pos, float tilt) {
|
void SomfyShade::moveToTarget(float pos, float tilt) {
|
||||||
|
ESP_LOGI(TAG, "[Shade %u] moveToTarget(pos=%.2f, tilt=%.2f) settingPos=%d direction=%d currentTarget=%.2f currentPos=%.2f",
|
||||||
|
this->getShadeId(), pos, tilt, this->settingPos, this->direction, this->target, this->currentPos);
|
||||||
somfy_commands cmd = somfy_commands::My;
|
somfy_commands cmd = somfy_commands::My;
|
||||||
if(this->isToggle()) {
|
if(this->isToggle()) {
|
||||||
// Overload this as we cannot seek a position on a garage door or single button device.
|
// Overload this as we cannot seek a position on a garage door or single button device.
|
||||||
|
|
@ -3042,7 +3046,9 @@ bool SomfyShade::save() {
|
||||||
if(somfy.useNVS()) {
|
if(somfy.useNVS()) {
|
||||||
char shadeKey[15];
|
char shadeKey[15];
|
||||||
snprintf(shadeKey, sizeof(shadeKey), "SomfyShade%u", this->getShadeId());
|
snprintf(shadeKey, sizeof(shadeKey), "SomfyShade%u", this->getShadeId());
|
||||||
pref.begin(shadeKey);
|
if(!pref.begin(shadeKey)) {
|
||||||
|
ESP_LOGE(TAG, "[Shade %u] save() pref.begin(%s) FAILED", this->getShadeId(), shadeKey);
|
||||||
|
}
|
||||||
pref.clear();
|
pref.clear();
|
||||||
pref.putChar("shadeType", static_cast<uint8_t>(this->shadeType));
|
pref.putChar("shadeType", static_cast<uint8_t>(this->shadeType));
|
||||||
pref.putUInt("remoteAddress", this->getRemoteAddress());
|
pref.putUInt("remoteAddress", this->getRemoteAddress());
|
||||||
|
|
@ -3915,7 +3921,9 @@ bool SomfyShadeController::deleteGroup(uint8_t groupId) {
|
||||||
|
|
||||||
bool SomfyShadeController::loadShadesFile(const char *filename) { return ShadeConfigFile::load(this, filename); }
|
bool SomfyShadeController::loadShadesFile(const char *filename) { return ShadeConfigFile::load(this, filename); }
|
||||||
uint16_t SomfyRemote::getNextRollingCode() {
|
uint16_t SomfyRemote::getNextRollingCode() {
|
||||||
pref.begin("ShadeCodes");
|
if(!pref.begin("ShadeCodes")) {
|
||||||
|
ESP_LOGE(TAG, "getNextRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||||
|
}
|
||||||
uint16_t code = pref.getUShort(this->m_remotePrefId, 0);
|
uint16_t code = pref.getUShort(this->m_remotePrefId, 0);
|
||||||
code++;
|
code++;
|
||||||
pref.putUShort(this->m_remotePrefId, code);
|
pref.putUShort(this->m_remotePrefId, code);
|
||||||
|
|
|
||||||
171
src/Web.cpp
171
src/Web.cpp
|
|
@ -43,10 +43,15 @@ static const char _encoding_json[] = "application/json";
|
||||||
|
|
||||||
static const char *TAG = "Web";
|
static const char *TAG = "Web";
|
||||||
|
|
||||||
|
static QueueHandle_t webCmdQueue = nullptr;
|
||||||
|
static SemaphoreHandle_t webCmdDone = nullptr;
|
||||||
|
|
||||||
AsyncWebServer asyncServer(80);
|
AsyncWebServer asyncServer(80);
|
||||||
AsyncWebServer asyncApiServer(8081);
|
AsyncWebServer asyncApiServer(8081);
|
||||||
void Web::startup() {
|
void Web::startup() {
|
||||||
ESP_LOGI(TAG, "Launching web server...");
|
ESP_LOGI(TAG, "Launching web server...");
|
||||||
|
if(!webCmdQueue) webCmdQueue = xQueueCreate(WEB_CMD_QUEUE_SIZE, sizeof(web_command_t));
|
||||||
|
if(!webCmdDone) webCmdDone = xSemaphoreCreateBinary();
|
||||||
|
|
||||||
asyncServer.on("/loginContext", HTTP_GET, [](AsyncWebServerRequest *request) {
|
asyncServer.on("/loginContext", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
AsyncJsonResponse *response = new AsyncJsonResponse();
|
AsyncJsonResponse *response = new AsyncJsonResponse();
|
||||||
|
|
@ -64,8 +69,96 @@ void Web::startup() {
|
||||||
ESP_LOGI(TAG, "Async API server started on port 8081");
|
ESP_LOGI(TAG, "Async API server started on port 8081");
|
||||||
}
|
}
|
||||||
void Web::loop() {
|
void Web::loop() {
|
||||||
|
this->processQueue();
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
bool Web::queueCommand(const web_command_t &cmd) {
|
||||||
|
if(!webCmdQueue || !webCmdDone) return false;
|
||||||
|
// Clear any stale signal
|
||||||
|
xSemaphoreTake(webCmdDone, 0);
|
||||||
|
if(xQueueSend(webCmdQueue, &cmd, pdMS_TO_TICKS(100)) != pdTRUE) {
|
||||||
|
ESP_LOGE(TAG, "Command queue full, dropping command");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Wait for main loop to process it
|
||||||
|
if(xSemaphoreTake(webCmdDone, pdMS_TO_TICKS(WEB_CMD_TIMEOUT_MS)) != pdTRUE) {
|
||||||
|
ESP_LOGW(TAG, "Command queue timeout waiting for processing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Web::processQueue() {
|
||||||
|
if(!webCmdQueue || !webCmdDone) return;
|
||||||
|
web_command_t cmd;
|
||||||
|
while(xQueueReceive(webCmdQueue, &cmd, 0) == pdTRUE) {
|
||||||
|
switch(cmd.type) {
|
||||||
|
case web_cmd_t::shade_command: {
|
||||||
|
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
|
||||||
|
if(shade) {
|
||||||
|
if(cmd.target <= 100) shade->moveToTarget(shade->transformPosition(cmd.target));
|
||||||
|
else shade->sendCommand(cmd.command, cmd.repeat > 0 ? cmd.repeat : shade->repeats, cmd.stepSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::group_command: {
|
||||||
|
SomfyGroup *group = somfy.getGroupById(cmd.groupId);
|
||||||
|
if(group) group->sendCommand(cmd.command, cmd.repeat >= 0 ? cmd.repeat : group->repeats, cmd.stepSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::tilt_command: {
|
||||||
|
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
|
||||||
|
if(shade) {
|
||||||
|
if(cmd.target <= 100) shade->moveToTiltTarget(shade->transformPosition(cmd.target));
|
||||||
|
else shade->sendTiltCommand(cmd.command);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::shade_repeat: {
|
||||||
|
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
|
||||||
|
if(shade) {
|
||||||
|
if(shade->shadeType == shade_types::garage1 && cmd.command == somfy_commands::Prog) cmd.command = somfy_commands::Toggle;
|
||||||
|
if(!shade->isLastCommand(cmd.command)) shade->sendCommand(cmd.command, cmd.repeat >= 0 ? cmd.repeat : shade->repeats, cmd.stepSize);
|
||||||
|
else shade->repeatFrame(cmd.repeat >= 0 ? cmd.repeat : shade->repeats);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::group_repeat: {
|
||||||
|
SomfyGroup *group = somfy.getGroupById(cmd.groupId);
|
||||||
|
if(group) {
|
||||||
|
if(!group->isLastCommand(cmd.command)) group->sendCommand(cmd.command, cmd.repeat >= 0 ? cmd.repeat : group->repeats, cmd.stepSize);
|
||||||
|
else group->repeatFrame(cmd.repeat >= 0 ? cmd.repeat : group->repeats);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::set_positions: {
|
||||||
|
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
|
||||||
|
if(shade) {
|
||||||
|
if(cmd.position >= 0) shade->target = shade->currentPos = cmd.position;
|
||||||
|
if(cmd.tiltPosition >= 0 && shade->tiltType != tilt_types::none) shade->tiltTarget = shade->currentTiltPos = cmd.tiltPosition;
|
||||||
|
shade->emitState();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::shade_sensor: {
|
||||||
|
SomfyShade *shade = somfy.getShadeById(cmd.shadeId);
|
||||||
|
if(shade) {
|
||||||
|
shade->sendSensorCommand(cmd.windy, cmd.sunny, cmd.repeat >= 0 ? (uint8_t)cmd.repeat : shade->repeats);
|
||||||
|
shade->emitState();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case web_cmd_t::group_sensor: {
|
||||||
|
SomfyGroup *group = somfy.getGroupById(cmd.groupId);
|
||||||
|
if(group) {
|
||||||
|
group->sendSensorCommand(cmd.windy, cmd.sunny, cmd.repeat >= 0 ? (uint8_t)cmd.repeat : group->repeats);
|
||||||
|
group->emitState();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(webCmdDone);
|
||||||
|
}
|
||||||
|
}
|
||||||
bool Web::isAuthenticated(AsyncWebServerRequest *request, bool cfg) {
|
bool Web::isAuthenticated(AsyncWebServerRequest *request, bool cfg) {
|
||||||
ESP_LOGD(TAG, "Checking async authentication");
|
ESP_LOGD(TAG, "Checking async authentication");
|
||||||
if(settings.Security.type == security_types::None) return true;
|
if(settings.Security.type == security_types::None) return true;
|
||||||
|
|
@ -521,8 +614,15 @@ void Web::handleShadeCommand(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); return; }
|
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); return; }
|
||||||
SomfyShade *shade = somfy.getShadeById(shadeId);
|
SomfyShade *shade = somfy.getShadeById(shadeId);
|
||||||
if(shade) {
|
if(shade) {
|
||||||
if(target <= 100) shade->moveToTarget(shade->transformPosition(target));
|
ESP_LOGI(TAG, "handleShadeCommand shade=%u target=%u command=%s", shadeId, target, translateSomfyCommand(command).c_str());
|
||||||
else shade->sendCommand(command, repeat > 0 ? repeat : shade->repeats, stepSize);
|
web_command_t cmd = {};
|
||||||
|
cmd.type = web_cmd_t::shade_command;
|
||||||
|
cmd.shadeId = shadeId;
|
||||||
|
cmd.target = target;
|
||||||
|
cmd.command = command;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
cmd.stepSize = stepSize;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -556,7 +656,14 @@ void Web::handleGroupCommand(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No group object supplied.\"}")); return; }
|
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No group object supplied.\"}")); return; }
|
||||||
SomfyGroup *group = somfy.getGroupById(groupId);
|
SomfyGroup *group = somfy.getGroupById(groupId);
|
||||||
if(group) {
|
if(group) {
|
||||||
group->sendCommand(command, repeat >= 0 ? repeat : group->repeats, stepSize);
|
ESP_LOGI(TAG, "handleGroupCommand group=%u command=%s", groupId, translateSomfyCommand(command).c_str());
|
||||||
|
web_command_t cmd = {};
|
||||||
|
cmd.type = web_cmd_t::group_command;
|
||||||
|
cmd.groupId = groupId;
|
||||||
|
cmd.command = command;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
cmd.stepSize = stepSize;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -587,8 +694,13 @@ void Web::handleTiltCommand(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); return; }
|
else { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"No shade object supplied.\"}")); return; }
|
||||||
SomfyShade *shade = somfy.getShadeById(shadeId);
|
SomfyShade *shade = somfy.getShadeById(shadeId);
|
||||||
if(shade) {
|
if(shade) {
|
||||||
if(target <= 100) shade->moveToTiltTarget(shade->transformPosition(target));
|
ESP_LOGI(TAG, "handleTiltCommand shade=%u target=%u command=%s", shadeId, target, translateSomfyCommand(command).c_str());
|
||||||
else shade->sendTiltCommand(command);
|
web_command_t cmd = {};
|
||||||
|
cmd.type = web_cmd_t::tilt_command;
|
||||||
|
cmd.shadeId = shadeId;
|
||||||
|
cmd.target = target;
|
||||||
|
cmd.command = command;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -620,11 +732,16 @@ void Web::handleRepeatCommand(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
if(!obj["repeat"].isNull()) repeat = obj["repeat"].as<uint8_t>();
|
if(!obj["repeat"].isNull()) repeat = obj["repeat"].as<uint8_t>();
|
||||||
}
|
}
|
||||||
if(shadeId != 255) {
|
if(shadeId != 255) {
|
||||||
|
ESP_LOGI(TAG, "handleRepeatCommand shade=%u command=%s", shadeId, translateSomfyCommand(command).c_str());
|
||||||
SomfyShade *shade = somfy.getShadeById(shadeId);
|
SomfyShade *shade = somfy.getShadeById(shadeId);
|
||||||
if(!shade) { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade reference could not be found.\"}")); return; }
|
if(!shade) { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Shade reference could not be found.\"}")); return; }
|
||||||
if(shade->shadeType == shade_types::garage1 && command == somfy_commands::Prog) command = somfy_commands::Toggle;
|
web_command_t cmd = {};
|
||||||
if(!shade->isLastCommand(command)) shade->sendCommand(command, repeat >= 0 ? repeat : shade->repeats, stepSize);
|
cmd.type = web_cmd_t::shade_repeat;
|
||||||
else shade->repeatFrame(repeat >= 0 ? repeat : shade->repeats);
|
cmd.shadeId = shadeId;
|
||||||
|
cmd.command = command;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
cmd.stepSize = stepSize;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginArray();
|
resp.beginArray();
|
||||||
|
|
@ -633,10 +750,16 @@ void Web::handleRepeatCommand(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
resp.endResponse();
|
resp.endResponse();
|
||||||
}
|
}
|
||||||
else if(groupId != 255) {
|
else if(groupId != 255) {
|
||||||
|
ESP_LOGI(TAG, "handleRepeatCommand group=%u command=%s", groupId, translateSomfyCommand(command).c_str());
|
||||||
SomfyGroup *group = somfy.getGroupById(groupId);
|
SomfyGroup *group = somfy.getGroupById(groupId);
|
||||||
if(!group) { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Group reference could not be found.\"}")); return; }
|
if(!group) { request->send(500, _encoding_json, F("{\"status\":\"ERROR\",\"desc\":\"Group reference could not be found.\"}")); return; }
|
||||||
if(!group->isLastCommand(command)) group->sendCommand(command, repeat >= 0 ? repeat : group->repeats, stepSize);
|
web_command_t cmd = {};
|
||||||
else group->repeatFrame(repeat >= 0 ? repeat : group->repeats);
|
cmd.type = web_cmd_t::group_repeat;
|
||||||
|
cmd.groupId = groupId;
|
||||||
|
cmd.command = command;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
cmd.stepSize = stepSize;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -722,11 +845,15 @@ void Web::handleSetPositions(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
if(!obj["tiltPosition"].isNull()) tiltPos = obj["tiltPosition"];
|
if(!obj["tiltPosition"].isNull()) tiltPos = obj["tiltPosition"];
|
||||||
}
|
}
|
||||||
if(shadeId != 255) {
|
if(shadeId != 255) {
|
||||||
|
ESP_LOGI(TAG, "handleSetPositions shade=%u pos=%d tiltPos=%d", shadeId, pos, tiltPos);
|
||||||
SomfyShade *shade = somfy.getShadeById(shadeId);
|
SomfyShade *shade = somfy.getShadeById(shadeId);
|
||||||
if(shade) {
|
if(shade) {
|
||||||
if(pos >= 0) shade->target = shade->currentPos = pos;
|
web_command_t cmd = {};
|
||||||
if(tiltPos >= 0 && shade->tiltType != tilt_types::none) shade->tiltTarget = shade->currentTiltPos = tiltPos;
|
cmd.type = web_cmd_t::set_positions;
|
||||||
shade->emitState();
|
cmd.shadeId = shadeId;
|
||||||
|
cmd.position = pos;
|
||||||
|
cmd.tiltPosition = tiltPos;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -763,8 +890,13 @@ void Web::handleSetSensor(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
if(shadeId != 255) {
|
if(shadeId != 255) {
|
||||||
SomfyShade *shade = somfy.getShadeById(shadeId);
|
SomfyShade *shade = somfy.getShadeById(shadeId);
|
||||||
if(shade) {
|
if(shade) {
|
||||||
shade->sendSensorCommand(windy, sunny, repeat >= 0 ? (uint8_t)repeat : shade->repeats);
|
web_command_t cmd = {};
|
||||||
shade->emitState();
|
cmd.type = web_cmd_t::shade_sensor;
|
||||||
|
cmd.shadeId = shadeId;
|
||||||
|
cmd.sunny = sunny;
|
||||||
|
cmd.windy = windy;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
@ -777,8 +909,13 @@ void Web::handleSetSensor(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
else if(groupId != 255) {
|
else if(groupId != 255) {
|
||||||
SomfyGroup *group = somfy.getGroupById(groupId);
|
SomfyGroup *group = somfy.getGroupById(groupId);
|
||||||
if(group) {
|
if(group) {
|
||||||
group->sendSensorCommand(windy, sunny, repeat >= 0 ? (uint8_t)repeat : group->repeats);
|
web_command_t cmd = {};
|
||||||
group->emitState();
|
cmd.type = web_cmd_t::group_sensor;
|
||||||
|
cmd.groupId = groupId;
|
||||||
|
cmd.sunny = sunny;
|
||||||
|
cmd.windy = windy;
|
||||||
|
cmd.repeat = repeat;
|
||||||
|
this->queueCommand(cmd);
|
||||||
AsyncJsonResp resp;
|
AsyncJsonResp resp;
|
||||||
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
|
||||||
resp.beginObject();
|
resp.beginObject();
|
||||||
|
|
|
||||||
34
src/Web.h
34
src/Web.h
|
|
@ -1,8 +1,39 @@
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
#include "Somfy.h"
|
#include "Somfy.h"
|
||||||
#ifndef webserver_h
|
#ifndef webserver_h
|
||||||
#define webserver_h
|
#define webserver_h
|
||||||
|
|
||||||
|
#define WEB_CMD_QUEUE_SIZE 8
|
||||||
|
#define WEB_CMD_TIMEOUT_MS 3000
|
||||||
|
|
||||||
|
enum class web_cmd_t : uint8_t {
|
||||||
|
shade_command, // moveToTarget or sendCommand
|
||||||
|
group_command, // group sendCommand
|
||||||
|
tilt_command, // moveToTiltTarget or sendTiltCommand
|
||||||
|
shade_repeat, // shade sendCommand/repeatFrame
|
||||||
|
group_repeat, // group sendCommand/repeatFrame
|
||||||
|
set_positions, // set shade position directly
|
||||||
|
shade_sensor, // shade sensor command
|
||||||
|
group_sensor, // group sensor command
|
||||||
|
};
|
||||||
|
|
||||||
|
struct web_command_t {
|
||||||
|
web_cmd_t type;
|
||||||
|
uint8_t shadeId;
|
||||||
|
uint8_t groupId;
|
||||||
|
uint8_t target; // 0-100 or 255 (none)
|
||||||
|
somfy_commands command;
|
||||||
|
int8_t repeat;
|
||||||
|
uint8_t stepSize;
|
||||||
|
int8_t position; // for setPositions
|
||||||
|
int8_t tiltPosition; // for setPositions/tilt
|
||||||
|
int8_t sunny; // for sensor
|
||||||
|
int8_t windy; // for sensor
|
||||||
|
};
|
||||||
|
|
||||||
class Web {
|
class Web {
|
||||||
public:
|
public:
|
||||||
bool uploadSuccess = false;
|
bool uploadSuccess = false;
|
||||||
|
|
@ -36,5 +67,8 @@ class Web {
|
||||||
void handleBackup(AsyncWebServerRequest *request);
|
void handleBackup(AsyncWebServerRequest *request);
|
||||||
void handleReboot(AsyncWebServerRequest *request);
|
void handleReboot(AsyncWebServerRequest *request);
|
||||||
void handleNotFound(AsyncWebServerRequest *request);
|
void handleNotFound(AsyncWebServerRequest *request);
|
||||||
|
private:
|
||||||
|
void processQueue();
|
||||||
|
bool queueCommand(const web_command_t &cmd);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue