Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/OpenThermTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@ class OpenThermTask : public Task {
delete this->instance;
}

struct ReadResult{

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переименовать в ExternalRequest

bool valid = false;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавить поле status:

OpenThermStatus status = OpenThermStatus::NOT_INITIALIZED;

bool parityValid = false;
bool responseMessageIdValid = false;
const char* responseType = "";
uint16_t value = 0;
};

ReadResult readRequest(byte messageId) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вместо этого добавить метод sendExternalRequest(OpenThermMessageID id, unsigned int data), который будет заполнять структуру ExternalRequest. При вызове метода устанавливать статус OpenThermStatus::RESPONSE_WAITING.
И было бы здорово иметь возможность отправлять данные, а не только читать значение по ID'у :)

Добавить метод bool hasReadyExternalRequest(), который будет проверять статус.
Добавить метод unsigned long getResponseExternalRequest(), который будет возвращать респонс из ExternalRequest.

Внутри OpenThermTask::loop() проверять статус ExternalRequest, если он OpenThermStatus::RESPONSE_WAITING, то делать this->instance->sendRequest(...) и заполнять ExternalRequest. Статус после выполнения запроса поменять на OpenThermStatus::RESPONSE_READY.

ReadResult result;
OpenThermMessageID eMessageId = (OpenThermMessageID)messageId;
auto response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermRequestType::READ_DATA,
eMessageId,
0
));
result.valid = CustomOpenTherm::isValidResponse(response);
result.parityValid = !CustomOpenTherm::parity(response);
result.responseMessageIdValid = CustomOpenTherm::isValidResponseId(response, eMessageId);
result.responseType = CustomOpenTherm::messageTypeToString(CustomOpenTherm::getMessageType(response));
result.value = CustomOpenTherm::getUInt(response);
return result;
}

protected:
const unsigned short readyTime = 60000u;
const unsigned int resetBusInterval = 120000u;
Expand Down
48 changes: 48 additions & 0 deletions src/PortalTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ using namespace NetworkUtils;
extern NetworkMgr* network;
extern FileData fsNetworkSettings, fsSettings, fsSensorsSettings;
extern MqttTask* tMqtt;
extern OpenThermTask* tOt;


class PortalTask : public LeanTask {
Expand Down Expand Up @@ -177,6 +178,18 @@ class PortalTask : public LeanTask {
});
this->webServer->addHandler(upgradePage);

// Opentherm request page
auto openthermRequestPage = (new StaticPage("/opentherm_request.html", &LittleFS, F("/pages/opentherm_request.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(BASIC_AUTH);
return false;
}

return true;
});
this->webServer->addHandler(openthermRequestPage);

// OTA
auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) {
if (this->isAuthRequired() && !this->isValidCredentials()) {
Expand Down Expand Up @@ -841,6 +854,41 @@ class PortalTask : public LeanTask {
this->bufferedWebServer->send(200, F("application/json"), doc, true);
});

this->webServer->on(F("/api/opentherm_request/read"), HTTP_POST, [this]() {
if (this->isAuthRequired() && !this->isValidCredentials()) {
return this->webServer->send(401);
}

const String& plain = this->webServer->arg(0);
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Request /api/opentherm_request/read %d bytes: %s"), plain.length(), plain.c_str());

JsonDocument doc;
DeserializationError dErr = deserializeJson(doc, plain);

if (dErr != DeserializationError::Ok || doc.isNull() || !doc.size()) {
this->webServer->send(400);
return;
}

if (doc[FPSTR(S_MESSAGE_ID)].isNull() || !doc[FPSTR(S_MESSAGE_ID)].is<byte>()) {
this->webServer->send(400);
return;
}
auto messageId = doc[FPSTR(S_MESSAGE_ID)].as<byte>();
doc.clear();
doc.shrinkToFit();

auto result = tOt->readRequest(messageId);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вместо этого вызывать tOt->sendExternalRequest(...)


doc[FPSTR(S_VALID)] = result.valid;
doc[FPSTR(S_PARITY_VALID)] = result.parityValid;
doc[FPSTR(S_RESPONSE_MESSAGE_ID_VALID)] = result.responseMessageIdValid;
doc[FPSTR(S_RESPONSE_TYPE)] = result.responseType;
doc[FPSTR(S_VALUE)] = result.value;
doc.shrinkToFit();

this->bufferedWebServer->send(200, F("application/json"), doc);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Просто вернуть пустой ответ с кодом 200

});

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавить обработчик для чтения данных через tOt->getResponseExternalRequest() если tOt->hasReadyExternalRequest() == true и вывод клиенту json с данными


// not found
this->webServer->onNotFound([this]() {
Expand Down
5 changes: 5 additions & 0 deletions src/strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const char S_MAX_POWER[] PROGMEM = "maxPower";
const char S_MAX_TEMP[] PROGMEM = "maxTemp";
const char S_MAX_TEMP_SYNC_WITH_TARGET_TEMP[] PROGMEM = "maxTempSyncWithTargetTemp";
const char S_MEMBER_ID[] PROGMEM = "memberId";
const char S_MESSAGE_ID[] PROGMEM = "messageId";
const char S_MIN[] PROGMEM = "min";
const char S_MIN_FREE[] PROGMEM = "minFree";
const char S_MIN_MAX_FREE_BLOCK[] PROGMEM = "minMaxFreeBlock";
Expand All @@ -147,6 +148,7 @@ const char S_OUTDOOR_TEMP[] PROGMEM = "outdoorTemp";
const char S_OUT_GPIO[] PROGMEM = "outGpio";
const char S_OUTPUT[] PROGMEM = "output";
const char S_PASSWORD[] PROGMEM = "password";
const char S_PARITY_VALID[] PROGMEM = "parityValid";
const char S_PID[] PROGMEM = "pid";
const char S_PORT[] PROGMEM = "port";
const char S_PORTAL[] PROGMEM = "portal";
Expand All @@ -163,6 +165,8 @@ const char S_RESET_DIAGNOSTIC[] PROGMEM = "resetDiagnostic";
const char S_RESET_FAULT[] PROGMEM = "resetFault";
const char S_RESET_REASON[] PROGMEM = "resetReason";
const char S_RESTART[] PROGMEM = "restart";
const char S_RESPONSE_MESSAGE_ID_VALID[] PROGMEM = "responseMessageIdValid";
const char S_RESPONSE_TYPE[] PROGMEM = "responseType";
const char S_RETURN_TEMP[] PROGMEM = "returnTemp";
const char S_REV[] PROGMEM = "rev";
const char S_RSSI[] PROGMEM = "rssi";
Expand Down Expand Up @@ -203,5 +207,6 @@ const char S_UPTIME[] PROGMEM = "uptime";
const char S_USE[] PROGMEM = "use";
const char S_USE_DHCP[] PROGMEM = "useDhcp";
const char S_USER[] PROGMEM = "user";
const char S_VALID[] PROGMEM = "valid";
const char S_VALUE[] PROGMEM = "value";
const char S_VERSION[] PROGMEM = "version";
28 changes: 27 additions & 1 deletion src_data/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"wait": "Please wait...",
"uploading": "Uploading...",
"success": "Success",
"error": "Error"
"error": "Error",
"send": "Send"
},

"index": {
Expand Down Expand Up @@ -467,6 +468,31 @@
"settingsFile": "Settings file",
"fw": "Firmware",
"fs": "Filesystem"
},

"opentherm_request": {
"title": "Custom requests - OpenTherm Gateway",
"name": "Custom requests",
"section": {
"read": "Read",
"read.desc": "Send a read request with a custom message ID"
},
"messageId": "Message ID",
"result": {
"valid": "Valid",
"parityValid": "Parity valid",
"responseMessageIdValid": "Response message ID valid",
"responseType": "Response type",
"data": "Data value",
"flags": "As flags",
"hex": "As hex",
"fixedPoint": "As f8.8",
"u8": "As two u8",
"s8": "As two s8",
"u16": "As u16",
"s16": "As s16"
}

}
}
}
27 changes: 26 additions & 1 deletion src_data/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"wait": "Attendi...",
"uploading": "caricamento...",
"success": "Riuscito",
"error": "Errore"
"error": "Errore",
"send": "Invia"
},

"index": {
Expand Down Expand Up @@ -467,6 +468,30 @@
"settingsFile": "Settings file",
"fw": "Firmware",
"fs": "Filesystem"
},

"opentherm_request": {
"title": "Richiesta personalizzata - OpenTherm Gateway",
"name": "Richiesta personalizzata",
"section": {
"read": "Lettura",
"read.desc": "Invia una lettura con un ID messaggio personalizzato"
},
"messageId": "ID messaggio",
"result": {
"valid": "Valido",
"parityValid": "Parità valida",
"responseMessageIdValid": "ID messaggio di risposta valido",
"responseType": "Tipo risposta",
"data": "Valore",
"flags": "Formato flags",
"hex": "Formato esadecimale",
"fixedPoint": "Formato f8.8",
"u8": "Formato due u8",
"s8": "Formato due s8",
"u16": "Formato u16",
"s16": "Formato s16"
}
}
}
}
28 changes: 27 additions & 1 deletion src_data/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"wait": "Пожалуйста, подождите...",
"uploading": "Загрузка...",
"success": "Успешно",
"error": "Ошибка"
"error": "Ошибка",
"send": "Отправить"
},

"index": {
Expand Down Expand Up @@ -467,6 +468,31 @@
"settingsFile": "Файл настроек",
"fw": "Прошивка",
"fs": "Файловая система"
},

"opentherm_request": {
"title": "Специальные запросы - OpenTherm Gateway",
"name": "Специальные запросы",
"section": {
"read": "Чтение",
"read.desc": "В этом разделе вы можете отправить запрос на чтение с произвольным message ID."
},
"messageId": "Message ID",
"result": {
"valid": "Ответ верен",
"parityValid": "Чётность верна",
"responseMessageIdValid": "Message ID ответа верно",
"responseType": "Тип ответа",
"data": "Данные",
"flags": "В виде флагов",
"hex": "В шестнадцатеричном виде",
"fixedPoint": "В виде f8.8",
"u8": "В виде двух u8",
"s8": "В виде двух s8",
"u16": "В виде u16",
"s16": "В виде s16"
}

}
}
}
1 change: 1 addition & 0 deletions src_data/pages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ <h2 data-i18n>index.section.system</h2>
<a href="/settings.html" role="button" data-i18n>settings.name</a>
<a href="/sensors.html" role="button" data-i18n>sensors.name</a>
<a href="/upgrade.html" role="button" data-i18n>upgrade.name</a>
<a href="/opentherm_request.html" role="button" data-i18n>opentherm_request.name</a>
<a href="/restart.html" role="button" class="secondary restart" data-i18n>button.restart</a>
</div>
</div>
Expand Down
Loading