mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 21:44:55 +01:00
Introduce parse_number() helper function (#2659)
This commit is contained in:
parent
219b225ac0
commit
15f9677d33
15 changed files with 70 additions and 36 deletions
|
@ -103,21 +103,21 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
|
|||
break;
|
||||
}
|
||||
case READ_TARGET_TEMPERATURE: {
|
||||
this->target_temp_ = strtof(this->buf_, nullptr);
|
||||
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
||||
if (this->fahrenheit_)
|
||||
this->target_temp_ = ftoc(this->target_temp_);
|
||||
this->has_target_temp_ = true;
|
||||
break;
|
||||
}
|
||||
case SET_TARGET_TEMPERATURE: {
|
||||
this->target_temp_ = strtof(this->buf_, nullptr);
|
||||
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
||||
if (this->fahrenheit_)
|
||||
this->target_temp_ = ftoc(this->target_temp_);
|
||||
this->has_target_temp_ = true;
|
||||
break;
|
||||
}
|
||||
case READ_CURRENT_TEMPERATURE: {
|
||||
this->current_temp_ = strtof(this->buf_, nullptr);
|
||||
this->current_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
||||
if (this->fahrenheit_)
|
||||
this->current_temp_ = ftoc(this->current_temp_);
|
||||
this->has_current_temp_ = true;
|
||||
|
|
|
@ -74,7 +74,7 @@ void EZOSensor::loop() {
|
|||
if (buf[0] != 1)
|
||||
return;
|
||||
|
||||
float val = strtof((char *) &buf[1], nullptr);
|
||||
float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 1).value_or(0);
|
||||
this->publish_state(val);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ static const char *const TAG = "homeassistant.sensor";
|
|||
void HomeassistantSensor::setup() {
|
||||
api::global_api_server->subscribe_home_assistant_state(
|
||||
this->entity_id_, this->attribute_, [this](const std::string &state) {
|
||||
auto val = parse_float(state);
|
||||
auto val = parse_number<float>(state);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", state.c_str());
|
||||
this->publish_state(NAN);
|
||||
|
|
|
@ -44,7 +44,7 @@ void HrxlMaxsonarWrComponent::check_buffer_() {
|
|||
|
||||
if (this->buffer_.length() == MAX_DATA_LENGTH_BYTES && this->buffer_[0] == 'R' &&
|
||||
this->buffer_.back() == static_cast<char>(ASCII_CR)) {
|
||||
int millimeters = strtol(this->buffer_.substr(1, MAX_DATA_LENGTH_BYTES - 2).c_str(), nullptr, 10);
|
||||
int millimeters = parse_number<int>(this->buffer_.substr(1, MAX_DATA_LENGTH_BYTES - 2)).value_or(0);
|
||||
float meters = float(millimeters) / 1000.0;
|
||||
ESP_LOGV(TAG, "Distance from sensor: %d mm, %f m", millimeters, meters);
|
||||
this->publish_state(meters);
|
||||
|
|
|
@ -137,7 +137,7 @@ void MQTTClimateComponent::setup() {
|
|||
if (traits.get_supports_two_point_target_temperature()) {
|
||||
this->subscribe(this->get_target_temperature_low_command_topic(),
|
||||
[this](const std::string &topic, const std::string &payload) {
|
||||
auto val = parse_float(payload);
|
||||
auto val = parse_number<float>(payload);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
|
||||
return;
|
||||
|
@ -148,7 +148,7 @@ void MQTTClimateComponent::setup() {
|
|||
});
|
||||
this->subscribe(this->get_target_temperature_high_command_topic(),
|
||||
[this](const std::string &topic, const std::string &payload) {
|
||||
auto val = parse_float(payload);
|
||||
auto val = parse_number<float>(payload);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
|
||||
return;
|
||||
|
@ -160,7 +160,7 @@ void MQTTClimateComponent::setup() {
|
|||
} else {
|
||||
this->subscribe(this->get_target_temperature_command_topic(),
|
||||
[this](const std::string &topic, const std::string &payload) {
|
||||
auto val = parse_float(payload);
|
||||
auto val = parse_number<float>(payload);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
|
||||
return;
|
||||
|
|
|
@ -24,7 +24,7 @@ void MQTTCoverComponent::setup() {
|
|||
});
|
||||
if (traits.get_supports_position()) {
|
||||
this->subscribe(this->get_position_command_topic(), [this](const std::string &topic, const std::string &payload) {
|
||||
auto value = parse_float(payload);
|
||||
auto value = parse_number<float>(payload);
|
||||
if (!value.has_value()) {
|
||||
ESP_LOGW(TAG, "Invalid position value: '%s'", payload.c_str());
|
||||
return;
|
||||
|
@ -36,7 +36,7 @@ void MQTTCoverComponent::setup() {
|
|||
}
|
||||
if (traits.get_supports_tilt()) {
|
||||
this->subscribe(this->get_tilt_command_topic(), [this](const std::string &topic, const std::string &payload) {
|
||||
auto value = parse_float(payload);
|
||||
auto value = parse_number<float>(payload);
|
||||
if (!value.has_value()) {
|
||||
ESP_LOGW(TAG, "Invalid tilt value: '%s'", payload.c_str());
|
||||
return;
|
||||
|
|
|
@ -71,7 +71,7 @@ void MQTTFanComponent::setup() {
|
|||
if (this->state_->get_traits().supports_speed()) {
|
||||
this->subscribe(this->get_speed_level_command_topic(),
|
||||
[this](const std::string &topic, const std::string &payload) {
|
||||
optional<int> speed_level_opt = parse_int(payload);
|
||||
optional<int> speed_level_opt = parse_number<int>(payload);
|
||||
if (speed_level_opt.has_value()) {
|
||||
const int speed_level = speed_level_opt.value();
|
||||
if (speed_level >= 0 && speed_level <= this->state_->get_traits().supported_speed_count()) {
|
||||
|
|
|
@ -17,7 +17,7 @@ MQTTNumberComponent::MQTTNumberComponent(Number *number) : MQTTComponent(), numb
|
|||
|
||||
void MQTTNumberComponent::setup() {
|
||||
this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &state) {
|
||||
auto val = parse_float(state);
|
||||
auto val = parse_number<float>(state);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", state.c_str());
|
||||
return;
|
||||
|
|
|
@ -13,7 +13,7 @@ void MQTTSubscribeSensor::setup() {
|
|||
mqtt::global_mqtt_client->subscribe(
|
||||
this->topic_,
|
||||
[this](const std::string &topic, const std::string &payload) {
|
||||
auto val = parse_float(payload);
|
||||
auto val = parse_number<float>(payload);
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
|
||||
this->publish_state(NAN);
|
||||
|
|
|
@ -656,7 +656,7 @@ void Pipsolar::loop() {
|
|||
case 32:
|
||||
fc = tmp[i];
|
||||
fc += tmp[i + 1];
|
||||
this->value_fault_code_ = strtol(fc.c_str(), nullptr, 10);
|
||||
this->value_fault_code_ = parse_number<int>(fc).value_or(0);
|
||||
break;
|
||||
case 34:
|
||||
this->value_warnung_low_pv_energy_ = enabled;
|
||||
|
|
|
@ -128,7 +128,7 @@ void Sim800LComponent::parse_cmd_(std::string message) {
|
|||
if (message.compare(0, 5, "+CSQ:") == 0) {
|
||||
size_t comma = message.find(',', 6);
|
||||
if (comma != 6) {
|
||||
this->rssi_ = strtol(message.substr(6, comma - 6).c_str(), nullptr, 10);
|
||||
this->rssi_ = parse_number<int>(message.substr(6, comma - 6)).value_or(0);
|
||||
ESP_LOGD(TAG, "RSSI: %d", this->rssi_);
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ void Sim800LComponent::parse_cmd_(std::string message) {
|
|||
while (end != start) {
|
||||
item++;
|
||||
if (item == 1) { // Slot Index
|
||||
this->parse_index_ = strtol(message.substr(start, end - start).c_str(), nullptr, 10);
|
||||
this->parse_index_ = parse_number<uint8_t>(message.substr(start, end - start)).value_or(0);
|
||||
}
|
||||
// item 2 = STATUS, usually "REC UNERAD"
|
||||
if (item == 3) { // recipient
|
||||
|
|
|
@ -6,8 +6,8 @@ namespace teleinfo {
|
|||
static const char *const TAG = "teleinfo_sensor";
|
||||
TeleInfoSensor::TeleInfoSensor(const char *tag) { this->tag = std::string(tag); }
|
||||
void TeleInfoSensor::publish_val(const std::string &val) {
|
||||
auto newval = parse_float(val);
|
||||
publish_state(*newval);
|
||||
auto newval = parse_number<float>(val).value_or(0.0f);
|
||||
publish_state(newval);
|
||||
}
|
||||
void TeleInfoSensor::dump_config() { LOG_SENSOR(" ", "Teleinfo Sensor", this); }
|
||||
} // namespace teleinfo
|
||||
|
|
|
@ -458,7 +458,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
|||
}
|
||||
if (request->hasParam("speed_level")) {
|
||||
String speed_level = request->getParam("speed_level")->value();
|
||||
auto val = parse_int(speed_level.c_str());
|
||||
auto val = parse_number<int>(speed_level.c_str());
|
||||
if (!val.has_value()) {
|
||||
ESP_LOGW(TAG, "Can't convert '%s' to number!", speed_level.c_str());
|
||||
return;
|
||||
|
|
|
@ -279,20 +279,6 @@ std::string to_string(long double val) {
|
|||
sprintf(buf, "%Lf", val);
|
||||
return buf;
|
||||
}
|
||||
optional<float> parse_float(const std::string &str) {
|
||||
char *end;
|
||||
float value = ::strtof(str.c_str(), &end);
|
||||
if (end == nullptr || end != str.end().base())
|
||||
return {};
|
||||
return value;
|
||||
}
|
||||
optional<int> parse_int(const std::string &str) {
|
||||
char *end;
|
||||
int value = ::strtol(str.c_str(), &end, 10);
|
||||
if (end == nullptr || end != str.end().base())
|
||||
return {};
|
||||
return value;
|
||||
}
|
||||
|
||||
optional<int> parse_hex(const char chr) {
|
||||
int out = chr;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
@ -51,8 +53,6 @@ std::string to_string(unsigned long long val); // NOLINT
|
|||
std::string to_string(float val);
|
||||
std::string to_string(double val);
|
||||
std::string to_string(long double val);
|
||||
optional<float> parse_float(const std::string &str);
|
||||
optional<int> parse_int(const std::string &str);
|
||||
optional<int> parse_hex(const std::string &str, size_t start, size_t length);
|
||||
optional<int> parse_hex(char chr);
|
||||
/// Sanitize the hostname by removing characters that are not in the allowlist and truncating it to 63 chars.
|
||||
|
@ -304,4 +304,52 @@ template<typename T> T *new_buffer(size_t length) {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/// @name Parsing & formatting
|
||||
///@{
|
||||
|
||||
/// Parse a unsigned decimal number.
|
||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
||||
optional<T> parse_number(const char *str, size_t len) {
|
||||
char *end = nullptr;
|
||||
unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
|
||||
if (end == nullptr || end != str + len || value > std::numeric_limits<T>::max())
|
||||
return {};
|
||||
return value;
|
||||
}
|
||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
||||
optional<T> parse_number(const std::string &str) {
|
||||
return parse_number<T>(str.c_str(), str.length());
|
||||
}
|
||||
/// Parse a signed decimal number.
|
||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
||||
optional<T> parse_number(const char *str, size_t len) {
|
||||
char *end = nullptr;
|
||||
signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
|
||||
if (end == nullptr || end != str + len || value < std::numeric_limits<T>::min() ||
|
||||
value > std::numeric_limits<T>::max())
|
||||
return {};
|
||||
return value;
|
||||
}
|
||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
||||
optional<T> parse_number(const std::string &str) {
|
||||
return parse_number<T>(str.c_str(), str.length());
|
||||
}
|
||||
/// Parse a decimal floating-point number.
|
||||
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
||||
optional<T> parse_number(const char *str, size_t len) {
|
||||
char *end = nullptr;
|
||||
float value = ::strtof(str, &end);
|
||||
if (end == nullptr || end != str + len || value == HUGE_VALF)
|
||||
return {};
|
||||
return value;
|
||||
}
|
||||
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
||||
optional<T> parse_number(const std::string &str) {
|
||||
return parse_number<T>(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
} // namespace esphome
|
||||
|
|
Loading…
Reference in a new issue