mirror of
https://github.com/esphome/esphome.git
synced 2026-02-25 21:43:14 -07:00
Merge branch 'integration' into memory_api
This commit is contained in:
@@ -235,7 +235,7 @@ void GraphLegend::init(Graph *g) {
|
||||
std::string valstr =
|
||||
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
|
||||
if (this->units_) {
|
||||
valstr += trace->sensor_->get_unit_of_measurement();
|
||||
valstr += trace->sensor_->get_unit_of_measurement_ref().c_str();
|
||||
}
|
||||
this->font_value_->measure(valstr.c_str(), &fw, &fos, &fbl, &fh);
|
||||
if (fw > valw)
|
||||
@@ -371,7 +371,7 @@ void Graph::draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_of
|
||||
std::string valstr =
|
||||
value_accuracy_to_string(trace->sensor_->get_state(), trace->sensor_->get_accuracy_decimals());
|
||||
if (legend_->units_) {
|
||||
valstr += trace->sensor_->get_unit_of_measurement();
|
||||
valstr += trace->sensor_->get_unit_of_measurement_ref().c_str();
|
||||
}
|
||||
buff->printf(xv, yv, legend_->font_value_, trace->get_line_color(), TextAlign::TOP_CENTER, "%s", valstr.c_str());
|
||||
ESP_LOGV(TAG, " value: %s", valstr.c_str());
|
||||
|
||||
@@ -36,7 +36,7 @@ void MQTTAlarmControlPanelComponent::setup() {
|
||||
} else if (strcasecmp(payload.c_str(), "TRIGGERED") == 0) {
|
||||
call.triggered();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
}
|
||||
call.perform();
|
||||
});
|
||||
|
||||
@@ -31,8 +31,9 @@ MQTTBinarySensorComponent::MQTTBinarySensorComponent(binary_sensor::BinarySensor
|
||||
|
||||
void MQTTBinarySensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (!this->binary_sensor_->get_device_class().empty())
|
||||
root[MQTT_DEVICE_CLASS] = this->binary_sensor_->get_device_class();
|
||||
const auto device_class = this->binary_sensor_->get_device_class_ref();
|
||||
if (!device_class.empty())
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
if (this->binary_sensor_->is_status_binary_sensor())
|
||||
root[MQTT_PAYLOAD_ON] = mqtt::global_mqtt_client->get_availability().payload_available;
|
||||
if (this->binary_sensor_->is_status_binary_sensor())
|
||||
|
||||
@@ -20,7 +20,7 @@ void MQTTButtonComponent::setup() {
|
||||
if (payload == "PRESS") {
|
||||
this->button_->press();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
this->status_momentary_warning("state", 5000);
|
||||
}
|
||||
});
|
||||
@@ -33,8 +33,9 @@ void MQTTButtonComponent::dump_config() {
|
||||
void MQTTButtonComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
config.state_topic = false;
|
||||
if (!this->button_->get_device_class().empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = this->button_->get_device_class();
|
||||
const auto device_class = this->button_->get_device_class_ref();
|
||||
if (!device_class.empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
}
|
||||
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ bool MQTTComponent::send_discovery_() {
|
||||
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
|
||||
|
||||
if (discovery_info.clean) {
|
||||
ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name_().c_str());
|
||||
return global_mqtt_client->publish(this->get_discovery_topic_(discovery_info), "", 0, this->qos_, true);
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name_().c_str());
|
||||
|
||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
return global_mqtt_client->publish_json(
|
||||
@@ -85,12 +85,13 @@ bool MQTTComponent::send_discovery_() {
|
||||
}
|
||||
|
||||
// Fields from EntityBase
|
||||
root[MQTT_NAME] = this->get_entity()->has_own_name() ? this->friendly_name() : "";
|
||||
root[MQTT_NAME] = this->get_entity()->has_own_name() ? this->friendly_name_() : "";
|
||||
|
||||
if (this->is_disabled_by_default())
|
||||
if (this->is_disabled_by_default_())
|
||||
root[MQTT_ENABLED_BY_DEFAULT] = false;
|
||||
if (!this->get_icon().empty())
|
||||
root[MQTT_ICON] = this->get_icon();
|
||||
const auto icon_ref = this->get_icon_ref_();
|
||||
if (!icon_ref.empty())
|
||||
root[MQTT_ICON] = icon_ref;
|
||||
|
||||
const auto entity_category = this->get_entity()->get_entity_category();
|
||||
switch (entity_category) {
|
||||
@@ -122,7 +123,7 @@ bool MQTTComponent::send_discovery_() {
|
||||
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
|
||||
if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) {
|
||||
char friendly_name_hash[9];
|
||||
sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name()));
|
||||
sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name_()));
|
||||
friendly_name_hash[8] = 0; // ensure the hash-string ends with null
|
||||
root[MQTT_UNIQUE_ID] = get_mac_address() + "-" + this->component_type() + "-" + friendly_name_hash;
|
||||
} else {
|
||||
@@ -184,7 +185,7 @@ bool MQTTComponent::is_discovery_enabled() const {
|
||||
}
|
||||
|
||||
std::string MQTTComponent::get_default_object_id_() const {
|
||||
return str_sanitize(str_snake_case(this->friendly_name()));
|
||||
return str_sanitize(str_snake_case(this->friendly_name_()));
|
||||
}
|
||||
|
||||
void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
|
||||
@@ -268,9 +269,9 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
|
||||
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
|
||||
|
||||
// Pull these properties from EntityBase if not overridden
|
||||
std::string MQTTComponent::friendly_name() const { return this->get_entity()->get_name(); }
|
||||
std::string MQTTComponent::get_icon() const { return this->get_entity()->get_icon(); }
|
||||
bool MQTTComponent::is_disabled_by_default() const { return this->get_entity()->is_disabled_by_default(); }
|
||||
std::string MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
|
||||
StringRef MQTTComponent::get_icon_ref_() const { return this->get_entity()->get_icon_ref(); }
|
||||
bool MQTTComponent::is_disabled_by_default_() const { return this->get_entity()->is_disabled_by_default(); }
|
||||
bool MQTTComponent::is_internal() {
|
||||
if (this->has_custom_state_topic_) {
|
||||
// If the custom state_topic is null, return true as it is internal and should not publish
|
||||
|
||||
@@ -165,13 +165,13 @@ class MQTTComponent : public Component {
|
||||
virtual const EntityBase *get_entity() const = 0;
|
||||
|
||||
/// Get the friendly name of this MQTT component.
|
||||
virtual std::string friendly_name() const;
|
||||
std::string friendly_name_() const;
|
||||
|
||||
/// Get the icon field of this component
|
||||
virtual std::string get_icon() const;
|
||||
/// Get the icon field of this component as StringRef
|
||||
StringRef get_icon_ref_() const;
|
||||
|
||||
/// Get whether the underlying Entity is disabled by default
|
||||
virtual bool is_disabled_by_default() const;
|
||||
bool is_disabled_by_default_() const;
|
||||
|
||||
/// Get the MQTT topic that new states will be shared to.
|
||||
std::string get_state_topic_() const;
|
||||
|
||||
@@ -68,8 +68,9 @@ void MQTTCoverComponent::dump_config() {
|
||||
}
|
||||
void MQTTCoverComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (!this->cover_->get_device_class().empty())
|
||||
root[MQTT_DEVICE_CLASS] = this->cover_->get_device_class();
|
||||
const auto device_class = this->cover_->get_device_class_ref();
|
||||
if (!device_class.empty())
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
|
||||
auto traits = this->cover_->get_traits();
|
||||
if (traits.get_is_assumed_state()) {
|
||||
|
||||
@@ -21,8 +21,9 @@ void MQTTEventComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConf
|
||||
for (const auto &event_type : this->event_->get_event_types())
|
||||
event_types.add(event_type);
|
||||
|
||||
if (!this->event_->get_device_class().empty())
|
||||
root[MQTT_DEVICE_CLASS] = this->event_->get_device_class();
|
||||
const auto device_class = this->event_->get_device_class_ref();
|
||||
if (!device_class.empty())
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
|
||||
config.command_topic = false;
|
||||
}
|
||||
|
||||
@@ -24,15 +24,15 @@ void MQTTFanComponent::setup() {
|
||||
auto val = parse_on_off(payload.c_str());
|
||||
switch (val) {
|
||||
case PARSE_ON:
|
||||
ESP_LOGD(TAG, "'%s' Turning Fan ON.", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s' Turning Fan ON.", this->friendly_name_().c_str());
|
||||
this->state_->turn_on().perform();
|
||||
break;
|
||||
case PARSE_OFF:
|
||||
ESP_LOGD(TAG, "'%s' Turning Fan OFF.", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s' Turning Fan OFF.", this->friendly_name_().c_str());
|
||||
this->state_->turn_off().perform();
|
||||
break;
|
||||
case PARSE_TOGGLE:
|
||||
ESP_LOGD(TAG, "'%s' Toggling Fan.", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s' Toggling Fan.", this->friendly_name_().c_str());
|
||||
this->state_->toggle().perform();
|
||||
break;
|
||||
case PARSE_NONE:
|
||||
@@ -48,11 +48,11 @@ void MQTTFanComponent::setup() {
|
||||
auto val = parse_on_off(payload.c_str(), "forward", "reverse");
|
||||
switch (val) {
|
||||
case PARSE_ON:
|
||||
ESP_LOGD(TAG, "'%s': Setting direction FORWARD", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s': Setting direction FORWARD", this->friendly_name_().c_str());
|
||||
this->state_->make_call().set_direction(fan::FanDirection::FORWARD).perform();
|
||||
break;
|
||||
case PARSE_OFF:
|
||||
ESP_LOGD(TAG, "'%s': Setting direction REVERSE", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s': Setting direction REVERSE", this->friendly_name_().c_str());
|
||||
this->state_->make_call().set_direction(fan::FanDirection::REVERSE).perform();
|
||||
break;
|
||||
case PARSE_TOGGLE:
|
||||
@@ -75,11 +75,11 @@ void MQTTFanComponent::setup() {
|
||||
auto val = parse_on_off(payload.c_str(), "oscillate_on", "oscillate_off");
|
||||
switch (val) {
|
||||
case PARSE_ON:
|
||||
ESP_LOGD(TAG, "'%s': Setting oscillating ON", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s': Setting oscillating ON", this->friendly_name_().c_str());
|
||||
this->state_->make_call().set_oscillating(true).perform();
|
||||
break;
|
||||
case PARSE_OFF:
|
||||
ESP_LOGD(TAG, "'%s': Setting oscillating OFF", this->friendly_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s': Setting oscillating OFF", this->friendly_name_().c_str());
|
||||
this->state_->make_call().set_oscillating(false).perform();
|
||||
break;
|
||||
case PARSE_TOGGLE:
|
||||
|
||||
@@ -24,7 +24,7 @@ void MQTTLockComponent::setup() {
|
||||
} else if (strcasecmp(payload.c_str(), "OPEN") == 0) {
|
||||
this->lock_->open();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
this->status_momentary_warning("state", 5000);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,8 +44,9 @@ void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
|
||||
root[MQTT_MIN] = traits.get_min_value();
|
||||
root[MQTT_MAX] = traits.get_max_value();
|
||||
root[MQTT_STEP] = traits.get_step();
|
||||
if (!this->number_->traits.get_unit_of_measurement().empty())
|
||||
root[MQTT_UNIT_OF_MEASUREMENT] = this->number_->traits.get_unit_of_measurement();
|
||||
const auto unit_of_measurement = this->number_->traits.get_unit_of_measurement_ref();
|
||||
if (!unit_of_measurement.empty())
|
||||
root[MQTT_UNIT_OF_MEASUREMENT] = unit_of_measurement;
|
||||
switch (this->number_->traits.get_mode()) {
|
||||
case NUMBER_MODE_AUTO:
|
||||
break;
|
||||
@@ -56,8 +57,9 @@ void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
|
||||
root[MQTT_MODE] = "slider";
|
||||
break;
|
||||
}
|
||||
if (!this->number_->traits.get_device_class().empty())
|
||||
root[MQTT_DEVICE_CLASS] = this->number_->traits.get_device_class();
|
||||
const auto device_class = this->number_->traits.get_device_class_ref();
|
||||
if (!device_class.empty())
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
|
||||
config.command_topic = true;
|
||||
}
|
||||
|
||||
@@ -45,12 +45,14 @@ void MQTTSensorComponent::disable_expire_after() { this->expire_after_ = 0; }
|
||||
|
||||
void MQTTSensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (!this->sensor_->get_device_class().empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class();
|
||||
const auto device_class = this->sensor_->get_device_class_ref();
|
||||
if (!device_class.empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
}
|
||||
|
||||
if (!this->sensor_->get_unit_of_measurement().empty())
|
||||
root[MQTT_UNIT_OF_MEASUREMENT] = this->sensor_->get_unit_of_measurement();
|
||||
const auto unit_of_measurement = this->sensor_->get_unit_of_measurement_ref();
|
||||
if (!unit_of_measurement.empty())
|
||||
root[MQTT_UNIT_OF_MEASUREMENT] = unit_of_measurement;
|
||||
|
||||
if (this->get_expire_after() > 0)
|
||||
root[MQTT_EXPIRE_AFTER] = this->get_expire_after() / 1000;
|
||||
|
||||
@@ -29,7 +29,7 @@ void MQTTSwitchComponent::setup() {
|
||||
break;
|
||||
case PARSE_NONE:
|
||||
default:
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
this->status_momentary_warning("state", 5000);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ using namespace esphome::text_sensor;
|
||||
MQTTTextSensor::MQTTTextSensor(TextSensor *sensor) : sensor_(sensor) {}
|
||||
void MQTTTextSensor::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (!this->sensor_->get_device_class().empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class();
|
||||
const auto device_class = this->sensor_->get_device_class_ref();
|
||||
if (!device_class.empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
}
|
||||
config.command_topic = false;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ void MQTTUpdateComponent::setup() {
|
||||
if (payload == "INSTALL") {
|
||||
this->update_->perform();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown update payload: %s", this->friendly_name().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown update payload: %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
this->status_momentary_warning("state", 5000);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -50,8 +50,9 @@ void MQTTValveComponent::dump_config() {
|
||||
}
|
||||
void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (!this->valve_->get_device_class().empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = this->valve_->get_device_class();
|
||||
const auto device_class = this->valve_->get_device_class_ref();
|
||||
if (!device_class.empty()) {
|
||||
root[MQTT_DEVICE_CLASS] = device_class;
|
||||
}
|
||||
|
||||
auto traits = this->valve_->get_traits();
|
||||
|
||||
@@ -158,7 +158,7 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor
|
||||
stream->print(ESPHOME_F("\",name=\""));
|
||||
stream->print(relabel_name_(obj).c_str());
|
||||
stream->print(ESPHOME_F("\",unit=\""));
|
||||
stream->print(obj->get_unit_of_measurement().c_str());
|
||||
stream->print(obj->get_unit_of_measurement_ref().c_str());
|
||||
stream->print(ESPHOME_F("\"} "));
|
||||
stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str());
|
||||
stream->print(ESPHOME_F("\n"));
|
||||
|
||||
@@ -650,7 +650,7 @@ void Sprinkler::set_valve_run_duration(const optional<size_t> valve_number, cons
|
||||
return;
|
||||
}
|
||||
auto call = this->valve_[valve_number.value()].run_duration_number->make_call();
|
||||
if (this->valve_[valve_number.value()].run_duration_number->traits.get_unit_of_measurement() == MIN_STR) {
|
||||
if (this->valve_[valve_number.value()].run_duration_number->traits.get_unit_of_measurement_ref() == MIN_STR) {
|
||||
call.set_value(run_duration.value() / 60.0);
|
||||
} else {
|
||||
call.set_value(run_duration.value());
|
||||
@@ -732,7 +732,7 @@ uint32_t Sprinkler::valve_run_duration(const size_t valve_number) {
|
||||
return 0;
|
||||
}
|
||||
if (this->valve_[valve_number].run_duration_number != nullptr) {
|
||||
if (this->valve_[valve_number].run_duration_number->traits.get_unit_of_measurement() == MIN_STR) {
|
||||
if (this->valve_[valve_number].run_duration_number->traits.get_unit_of_measurement_ref() == MIN_STR) {
|
||||
return static_cast<uint32_t>(roundf(this->valve_[valve_number].run_duration_number->state * 60));
|
||||
} else {
|
||||
return static_cast<uint32_t>(roundf(this->valve_[valve_number].run_duration_number->state));
|
||||
|
||||
@@ -61,7 +61,9 @@ class EntityBase {
|
||||
}
|
||||
|
||||
// Get/set this entity's icon
|
||||
std::string get_icon() const;
|
||||
[[deprecated("Use get_icon_ref() instead for better performance (avoids string copy). Will stop working in ESPHome "
|
||||
"2026.5.0")]] std::string
|
||||
get_icon() const;
|
||||
void set_icon(const char *icon);
|
||||
StringRef get_icon_ref() const {
|
||||
static constexpr auto EMPTY_STRING = StringRef::from_lit("");
|
||||
@@ -158,7 +160,9 @@ class EntityBase {
|
||||
class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
|
||||
public:
|
||||
/// Get the device class, using the manual override if set.
|
||||
std::string get_device_class();
|
||||
[[deprecated("Use get_device_class_ref() instead for better performance (avoids string copy). Will stop working in "
|
||||
"ESPHome 2026.5.0")]] std::string
|
||||
get_device_class();
|
||||
/// Manually set the device class.
|
||||
void set_device_class(const char *device_class);
|
||||
/// Get the device class as StringRef
|
||||
@@ -174,7 +178,9 @@ class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
|
||||
class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming)
|
||||
public:
|
||||
/// Get the unit of measurement, using the manual override if set.
|
||||
std::string get_unit_of_measurement();
|
||||
[[deprecated("Use get_unit_of_measurement_ref() instead for better performance (avoids string copy). Will stop "
|
||||
"working in ESPHome 2026.5.0")]] std::string
|
||||
get_unit_of_measurement();
|
||||
/// Manually set the unit of measurement.
|
||||
void set_unit_of_measurement(const char *unit_of_measurement);
|
||||
/// Get the unit of measurement as StringRef
|
||||
|
||||
Reference in New Issue
Block a user