mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 08:19:52 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev
This commit is contained in:
@@ -192,6 +192,7 @@ class EMSESPDataForm extends Component<
|
|||||||
this.props.enqueueSnackbar('Write command sent to device', {
|
this.props.enqueueSnackbar('Write command sent to device', {
|
||||||
variant: 'success'
|
variant: 'success'
|
||||||
});
|
});
|
||||||
|
this.handleRowClick(selectedDevice);
|
||||||
} else if (response.status === 204) {
|
} else if (response.status === 204) {
|
||||||
this.props.enqueueSnackbar('Write command failed', {
|
this.props.enqueueSnackbar('Write command failed', {
|
||||||
variant: 'error'
|
variant: 'error'
|
||||||
@@ -315,7 +316,7 @@ class EMSESPDataForm extends Component<
|
|||||||
<TableRow
|
<TableRow
|
||||||
hover
|
hover
|
||||||
key={device.id}
|
key={device.id}
|
||||||
onClick={() => this.handleRowClick(device)}
|
onClick={() => this.handleRowClick(device.id)}
|
||||||
>
|
>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<CustomTooltip
|
<CustomTooltip
|
||||||
@@ -522,10 +523,10 @@ class EMSESPDataForm extends Component<
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleRowClick = (device: any) => {
|
handleRowClick = (device: any) => {
|
||||||
this.setState({ selectedDevice: device.id, deviceData: undefined });
|
this.setState({ selectedDevice: device, deviceData: undefined });
|
||||||
redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, {
|
redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ id: device.id }),
|
body: JSON.stringify({ id: device }),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class SensorForm extends React.Component<SensorFormProps> {
|
|||||||
]}
|
]}
|
||||||
label="Custom Offset (°C)"
|
label="Custom Offset (°C)"
|
||||||
name="offset"
|
name="offset"
|
||||||
|
type="number"
|
||||||
value={sensor.offset}
|
value={sensor.offset}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -45,6 +45,16 @@ enum CommandFlag : uint8_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// returns 0 if the command errored, 1 (TRUE) if ok, 2 if not found, 3 if error or 4 if not allowed
|
||||||
|
enum CommandRet: uint8_t {
|
||||||
|
ERRORED = 0,
|
||||||
|
OK,
|
||||||
|
NOT_FOUND,
|
||||||
|
ERROR,
|
||||||
|
NOT_ALLOWED
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
using cmdfunction_p = std::function<bool(const char * data, const int8_t id)>;
|
using cmdfunction_p = std::function<bool(const char * data, const int8_t id)>;
|
||||||
using cmdfunction_json_p = std::function<bool(const char * data, const int8_t id, JsonObject & json)>;
|
using cmdfunction_json_p = std::function<bool(const char * data, const int8_t id, JsonObject & json)>;
|
||||||
|
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ void EMSESPShell::add_console_commands() {
|
|||||||
|
|
||||||
const char * cmd = arguments[1].c_str();
|
const char * cmd = arguments[1].c_str();
|
||||||
|
|
||||||
uint8_t cmd_return = 1; // OK
|
uint8_t cmd_return = CommandRet::OK;
|
||||||
|
|
||||||
if (arguments.size() == 2) {
|
if (arguments.size() == 2) {
|
||||||
// no value specified, just the cmd
|
// no value specified, just the cmd
|
||||||
@@ -403,17 +403,17 @@ void EMSESPShell::add_console_commands() {
|
|||||||
cmd_return = Command::call(device_type, cmd, arguments[2].c_str(), true, atoi(arguments[3].c_str()), json);
|
cmd_return = Command::call(device_type, cmd, arguments[2].c_str(), true, atoi(arguments[3].c_str()), json);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_return == 1 && json.size()) {
|
if (cmd_return == CommandRet::OK && json.size()) {
|
||||||
serializeJsonPretty(doc, shell);
|
serializeJsonPretty(doc, shell);
|
||||||
shell.println();
|
shell.println();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_return == 2) {
|
if (cmd_return == CommandRet::NOT_FOUND) {
|
||||||
shell.println(F("Unknown command"));
|
shell.println(F("Unknown command"));
|
||||||
shell.print(F("Available commands are: "));
|
shell.print(F("Available commands are: "));
|
||||||
Command::show(shell, device_type, false); // non-verbose mode
|
Command::show(shell, device_type, false); // non-verbose mode
|
||||||
} else if (cmd_return == 3) {
|
} else if (cmd_return == CommandRet::ERROR) {
|
||||||
shell.println(F("Bad syntax"));
|
shell.println(F("Bad syntax"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ bool EMSESP::trace_raw_ = false;
|
|||||||
uint64_t EMSESP::tx_delay_ = 0;
|
uint64_t EMSESP::tx_delay_ = 0;
|
||||||
uint8_t EMSESP::bool_format_ = 1;
|
uint8_t EMSESP::bool_format_ = 1;
|
||||||
uint8_t EMSESP::enum_format_ = 1;
|
uint8_t EMSESP::enum_format_ = 1;
|
||||||
|
uint16_t EMSESP::wait_validate_ = 0;
|
||||||
|
|
||||||
// for a specific EMS device go and request data values
|
// for a specific EMS device go and request data values
|
||||||
// or if device_id is 0 it will fetch from all our known and active devices
|
// or if device_id is 0 it will fetch from all our known and active devices
|
||||||
@@ -839,6 +840,9 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
publish_device_values(emsdevice->device_type()); // publish to MQTT if we explicitly have too
|
publish_device_values(emsdevice->device_type()); // publish to MQTT if we explicitly have too
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (wait_validate_ == telegram->type_id) {
|
||||||
|
wait_validate_ = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,12 @@ class EMSESP {
|
|||||||
static void set_read_id(uint16_t id) {
|
static void set_read_id(uint16_t id) {
|
||||||
read_id_ = id;
|
read_id_ = id;
|
||||||
}
|
}
|
||||||
|
static bool wait_validate() {
|
||||||
|
return (wait_validate_ != 0);
|
||||||
|
}
|
||||||
|
static void wait_validate(uint16_t wait) {
|
||||||
|
wait_validate_ = wait;
|
||||||
|
}
|
||||||
|
|
||||||
enum Bus_status : uint8_t { BUS_STATUS_CONNECTED = 0, BUS_STATUS_TX_ERRORS, BUS_STATUS_OFFLINE };
|
enum Bus_status : uint8_t { BUS_STATUS_CONNECTED = 0, BUS_STATUS_TX_ERRORS, BUS_STATUS_OFFLINE };
|
||||||
static uint8_t bus_status();
|
static uint8_t bus_status();
|
||||||
@@ -264,6 +270,7 @@ class EMSESP {
|
|||||||
static uint64_t tx_delay_;
|
static uint64_t tx_delay_;
|
||||||
static uint8_t bool_format_;
|
static uint8_t bool_format_;
|
||||||
static uint8_t enum_format_;
|
static uint8_t enum_format_;
|
||||||
|
static uint16_t wait_validate_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
10
src/mqtt.cpp
10
src/mqtt.cpp
@@ -348,10 +348,10 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
// LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s), mf.device_type_, topic, cmd_only, message);
|
// LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s), mf.device_type_, topic, cmd_only, message);
|
||||||
// call command, assume admin authentication is allowed
|
// call command, assume admin authentication is allowed
|
||||||
uint8_t cmd_return = Command::call(mf.device_type_, cmd_only, message, true);
|
uint8_t cmd_return = Command::call(mf.device_type_, cmd_only, message, true);
|
||||||
if (cmd_return == 2) {
|
if (cmd_return == CommandRet::NOT_FOUND) {
|
||||||
LOG_ERROR(F("No matching cmd (%s) in topic %s"), cmd_only, topic);
|
LOG_ERROR(F("No matching cmd (%s) in topic %s"), cmd_only, topic);
|
||||||
Mqtt::publish(F_(response), "unknown");
|
Mqtt::publish(F_(response), "unknown");
|
||||||
} else if (cmd_return == 3) {
|
} else if (cmd_return == CommandRet::ERROR) {
|
||||||
LOG_ERROR(F("Invalid data with cmd (%s) in topic %s"), cmd_only, topic);
|
LOG_ERROR(F("Invalid data with cmd (%s) in topic %s"), cmd_only, topic);
|
||||||
Mqtt::publish(F_(response), "unknown");
|
Mqtt::publish(F_(response), "unknown");
|
||||||
}
|
}
|
||||||
@@ -381,7 +381,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
n = doc["id"];
|
n = doc["id"];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t cmd_return = 1; // OK
|
uint8_t cmd_return = CommandRet::OK;
|
||||||
JsonVariant data = doc["data"];
|
JsonVariant data = doc["data"];
|
||||||
|
|
||||||
if (data.is<const char *>()) {
|
if (data.is<const char *>()) {
|
||||||
@@ -402,10 +402,10 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_return == 2) {
|
if (cmd_return == CommandRet::NOT_FOUND) {
|
||||||
LOG_ERROR(F("No matching cmd (%s)"), command);
|
LOG_ERROR(F("No matching cmd (%s)"), command);
|
||||||
Mqtt::publish(F_(response), "unknown");
|
Mqtt::publish(F_(response), "unknown");
|
||||||
} else if (cmd_return == 3) {
|
} else if (cmd_return == CommandRet::ERROR) {
|
||||||
LOG_ERROR(F("Invalid data for cmd (%s)"), command);
|
LOG_ERROR(F("Invalid data for cmd (%s)"), command);
|
||||||
Mqtt::publish(F_(response), "unknown");
|
Mqtt::publish(F_(response), "unknown");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -431,6 +431,9 @@ void TxService::add(const uint8_t operation,
|
|||||||
} else {
|
} else {
|
||||||
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false, validateid); // add to back of queue
|
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false, validateid); // add to back of queue
|
||||||
}
|
}
|
||||||
|
if (validateid != 0) {
|
||||||
|
EMSESP::wait_validate(validateid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// builds a Tx telegram and adds to queue
|
// builds a Tx telegram and adds to queue
|
||||||
@@ -507,6 +510,9 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
|
|||||||
// tx_telegrams_.push_back(qtxt); // add to back of queue
|
// tx_telegrams_.push_back(qtxt); // add to back of queue
|
||||||
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to back of queue
|
tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false, validate_id); // add to back of queue
|
||||||
}
|
}
|
||||||
|
if (validate_id != 0) {
|
||||||
|
EMSESP::wait_validate(validate_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send a Tx telegram to request data from an EMS device
|
// send a Tx telegram to request data from an EMS device
|
||||||
@@ -570,6 +576,7 @@ void TxService::retry_tx(const uint8_t operation, const uint8_t * data, const ui
|
|||||||
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
|
if (++retry_count_ > MAXIMUM_TX_RETRIES) {
|
||||||
reset_retry_count(); // give up
|
reset_retry_count(); // give up
|
||||||
increment_telegram_fail_count(); // another Tx fail
|
increment_telegram_fail_count(); // another Tx fail
|
||||||
|
EMSESP::wait_validate(0); // do not wait for validation
|
||||||
|
|
||||||
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"),
|
LOG_ERROR(F("Last Tx %s operation failed after %d retries. Ignoring request: %s"),
|
||||||
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
(operation == Telegram::Operation::TX_WRITE) ? F("Write") : F("Read"),
|
||||||
|
|||||||
@@ -182,15 +182,15 @@ void WebAPIService::parse(AsyncWebServerRequest * request, std::string & device_
|
|||||||
uint8_t cmd_reply = Command::call(device_type, cmd_s.c_str(), (have_data ? value_s.c_str() : nullptr), authenticated, id_n, json);
|
uint8_t cmd_reply = Command::call(device_type, cmd_s.c_str(), (have_data ? value_s.c_str() : nullptr), authenticated, id_n, json);
|
||||||
|
|
||||||
// check for errors
|
// check for errors
|
||||||
if (cmd_reply == 2) {
|
if (cmd_reply == CommandRet::NOT_FOUND) {
|
||||||
delete response;
|
delete response;
|
||||||
send_message_response(request, 400, "Command not found"); // Bad Request
|
send_message_response(request, 400, "Command not found"); // Bad Request
|
||||||
return;
|
return;
|
||||||
} else if (cmd_reply == 3) {
|
} else if (cmd_reply == CommandRet::ERROR) {
|
||||||
delete response;
|
delete response;
|
||||||
send_message_response(request, 400, "Problems parsing elements"); // Bad Request
|
send_message_response(request, 400, "Problems parsing elements"); // Bad Request
|
||||||
return;
|
return;
|
||||||
} else if (cmd_reply == 4) {
|
} else if (cmd_reply == CommandRet::NOT_ALLOWED) {
|
||||||
delete response;
|
delete response;
|
||||||
send_message_response(request, 401, "Bad credentials"); // Unauthorized
|
send_message_response(request, 401, "Bad credentials"); // Unauthorized
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -100,6 +100,11 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant &
|
|||||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice) {
|
||||||
if (emsdevice->unique_id() == json["id"]) {
|
if (emsdevice->unique_id() == json["id"]) {
|
||||||
|
// wait max 2.5 sec for updated data (post_send_delay is 2 sec)
|
||||||
|
for (uint16_t i = 0; i < 2500 && EMSESP::wait_validate(); i++) {
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
EMSESP::wait_validate(0); // reset in case of timeout
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
emsdevice->generate_values_json_web(root);
|
emsdevice->generate_values_json_web(root);
|
||||||
@@ -130,7 +135,7 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant &
|
|||||||
if (emsdevice->unique_id() == id) {
|
if (emsdevice->unique_id() == id) {
|
||||||
const char * cmd = dv["c"];
|
const char * cmd = dv["c"];
|
||||||
uint8_t device_type = emsdevice->device_type();
|
uint8_t device_type = emsdevice->device_type();
|
||||||
uint8_t cmd_return = 1; // OK
|
uint8_t cmd_return = CommandRet::OK;
|
||||||
char s[10];
|
char s[10];
|
||||||
// the data could be in any format, but we need string
|
// the data could be in any format, but we need string
|
||||||
JsonVariant data = dv["v"];
|
JsonVariant data = dv["v"];
|
||||||
@@ -145,7 +150,7 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant &
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send "Write command sent to device" or "Write command failed"
|
// send "Write command sent to device" or "Write command failed"
|
||||||
AsyncWebServerResponse * response = request->beginResponse((cmd_return == 1) ? 200 : 204);
|
AsyncWebServerResponse * response = request->beginResponse((cmd_return == CommandRet::OK) ? 200 : 204);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -166,7 +171,7 @@ void WebDataService::write_sensor(AsyncWebServerRequest * request, JsonVariant &
|
|||||||
// if valid add.
|
// if valid add.
|
||||||
uint8_t no = sensor["no"];
|
uint8_t no = sensor["no"];
|
||||||
if (no > 0 && no < 100) {
|
if (no > 0 && no < 100) {
|
||||||
char name[25];
|
char name[20];
|
||||||
std::string id = sensor["id"];
|
std::string id = sensor["id"];
|
||||||
strlcpy(name, id.c_str(), sizeof(name));
|
strlcpy(name, id.c_str(), sizeof(name));
|
||||||
float offset = sensor["offset"]; // this will be a float value. We'll convert it to int and * 10 it
|
float offset = sensor["offset"]; // this will be a float value. We'll convert it to int and * 10 it
|
||||||
|
|||||||
Reference in New Issue
Block a user