From 58fa63ad88b2c441d5d765f6865f0a10dd08ebed Mon Sep 17 00:00:00 2001 From: stegm Date: Tue, 8 Feb 2022 10:27:22 +0100 Subject: [PATCH] Add Select for modbus (#3032) Co-authored-by: Oxan van Leeuwen --- CODEOWNERS | 1 + esphome/codegen.py | 1 + .../modbus_controller/modbus_controller.cpp | 104 +++++-------- .../modbus_controller/modbus_controller.h | 54 +++++-- .../modbus_controller/select/__init__.py | 142 ++++++++++++++++++ .../select/modbus_select.cpp | 86 +++++++++++ .../modbus_controller/select/modbus_select.h | 51 +++++++ esphome/cpp_generator.py | 4 +- esphome/cpp_types.py | 1 + 9 files changed, 361 insertions(+), 83 deletions(-) create mode 100644 esphome/components/modbus_controller/select/__init__.py create mode 100644 esphome/components/modbus_controller/select/modbus_select.cpp create mode 100644 esphome/components/modbus_controller/select/modbus_select.h diff --git a/CODEOWNERS b/CODEOWNERS index 931e699566..3326b7d90c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -115,6 +115,7 @@ esphome/components/modbus_controller/* @martgras esphome/components/modbus_controller/binary_sensor/* @martgras esphome/components/modbus_controller/number/* @martgras esphome/components/modbus_controller/output/* @martgras +esphome/components/modbus_controller/select/* @martgras @stegm esphome/components/modbus_controller/sensor/* @martgras esphome/components/modbus_controller/switch/* @martgras esphome/components/modbus_controller/text_sensor/* @martgras diff --git a/esphome/codegen.py b/esphome/codegen.py index 52191e05e2..b862a8ce86 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -63,6 +63,7 @@ from esphome.cpp_types import ( # noqa uint32, uint64, int32, + int64, const_char_ptr, NAN, esphome_ns, diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 8b6482b1dc..64046b9578 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -110,7 +110,8 @@ void ModbusController::queue_command(const ModbusCommandItem &command) { for (auto &item : command_queue_) { if (item->register_address == command.register_address && item->register_count == command.register_count && item->register_type == command.register_type && item->function_code == command.function_code) { - ESP_LOGW(TAG, "Duplicate modbus command found"); + ESP_LOGW(TAG, "Duplicate modbus command found: type=0x%x address=%u count=%u", + static_cast(command.register_type), command.register_address, command.register_count); // update the payload of the queued command // replaces a previous command item->payload = command.payload; @@ -360,8 +361,9 @@ ModbusCommandItem ModbusCommandItem::create_write_multiple_command(ModbusControl modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; for (auto v : values) { - cmd.payload.push_back((v / 256) & 0xFF); - cmd.payload.push_back(v & 0xFF); + auto decoded_value = decode_value(v); + cmd.payload.push_back(decoded_value[0]); + cmd.payload.push_back(decoded_value[1]); } return cmd; } @@ -416,7 +418,7 @@ ModbusCommandItem ModbusCommandItem::create_write_multiple_coils(ModbusControlle } ModbusCommandItem ModbusCommandItem::create_write_single_command(ModbusController *modbusdevice, uint16_t start_address, - int16_t value) { + uint16_t value) { ModbusCommandItem cmd; cmd.modbusdevice = modbusdevice; cmd.register_type = ModbusRegisterType::HOLDING; @@ -427,8 +429,10 @@ ModbusCommandItem ModbusCommandItem::create_write_single_command(ModbusControlle const std::vector &data) { modbusdevice->on_write_register_response(cmd.register_type, start_address, data); }; - cmd.payload.push_back((value / 256) & 0xFF); - cmd.payload.push_back((value % 256) & 0xFF); + + auto decoded_value = decode_value(value); + cmd.payload.push_back(decoded_value[0]); + cmd.payload.push_back(decoded_value[1]); return cmd; } @@ -463,84 +467,70 @@ bool ModbusCommandItem::send() { return true; } -std::vector float_to_payload(float value, SensorValueType value_type) { - union { - float float_value; - uint32_t raw; - } raw_to_float; - - std::vector data; - int32_t val; - +void number_to_payload(std::vector &data, int64_t value, SensorValueType value_type) { switch (value_type) { case SensorValueType::U_WORD: case SensorValueType::S_WORD: - // cast truncates the float do some rounding here - data.push_back(lroundf(value) & 0xFFFF); + data.push_back(value & 0xFFFF); break; case SensorValueType::U_DWORD: case SensorValueType::S_DWORD: - val = lroundf(value); - data.push_back((val & 0xFFFF0000) >> 16); - data.push_back(val & 0xFFFF); + case SensorValueType::FP32: + case SensorValueType::FP32_R: + data.push_back((value & 0xFFFF0000) >> 16); + data.push_back(value & 0xFFFF); break; case SensorValueType::U_DWORD_R: case SensorValueType::S_DWORD_R: - val = lroundf(value); - data.push_back(val & 0xFFFF); - data.push_back((val & 0xFFFF0000) >> 16); + data.push_back(value & 0xFFFF); + data.push_back((value & 0xFFFF0000) >> 16); break; - case SensorValueType::FP32: - raw_to_float.float_value = value; - data.push_back((raw_to_float.raw & 0xFFFF0000) >> 16); - data.push_back(raw_to_float.raw & 0xFFFF); + case SensorValueType::U_QWORD: + case SensorValueType::S_QWORD: + data.push_back((value & 0xFFFF000000000000) >> 48); + data.push_back((value & 0xFFFF00000000) >> 32); + data.push_back((value & 0xFFFF0000) >> 16); + data.push_back(value & 0xFFFF); break; - case SensorValueType::FP32_R: - raw_to_float.float_value = value; - data.push_back(raw_to_float.raw & 0xFFFF); - data.push_back((raw_to_float.raw & 0xFFFF0000) >> 16); + case SensorValueType::U_QWORD_R: + case SensorValueType::S_QWORD_R: + data.push_back(value & 0xFFFF); + data.push_back((value & 0xFFFF0000) >> 16); + data.push_back((value & 0xFFFF00000000) >> 32); + data.push_back((value & 0xFFFF000000000000) >> 48); break; default: - ESP_LOGE(TAG, "Invalid data type for modbus float to payload conversation"); + ESP_LOGE(TAG, "Invalid data type for modbus number to payload conversation: %d", + static_cast(value_type)); break; } - return data; } -float payload_to_float(const std::vector &data, SensorValueType sensor_value_type, uint8_t offset, - uint32_t bitmask) { - union { - float float_value; - uint32_t raw; - } raw_to_float; - +int64_t payload_to_number(const std::vector &data, SensorValueType sensor_value_type, uint8_t offset, + uint32_t bitmask) { int64_t value = 0; // int64_t because it can hold signed and unsigned 32 bits - float result = NAN; switch (sensor_value_type) { case SensorValueType::U_WORD: value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); // default is 0xFFFF ; - result = static_cast(value); break; case SensorValueType::U_DWORD: + case SensorValueType::FP32: value = get_data(data, offset); value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); - result = static_cast(value); break; case SensorValueType::U_DWORD_R: + case SensorValueType::FP32_R: value = get_data(data, offset); value = static_cast(value & 0xFFFF) << 16 | (value & 0xFFFF0000) >> 16; value = mask_and_shift_by_rightbit((uint32_t) value, bitmask); - result = static_cast(value); break; case SensorValueType::S_WORD: value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); // default is 0xFFFF ; - result = static_cast(value); break; case SensorValueType::S_DWORD: value = mask_and_shift_by_rightbit(get_data(data, offset), bitmask); - result = static_cast(value); break; case SensorValueType::S_DWORD_R: { value = get_data(data, offset); @@ -549,18 +539,14 @@ float payload_to_float(const std::vector &data, SensorValueType sensor_ uint32_t sign_bit = (value & 0x8000) << 16; value = mask_and_shift_by_rightbit( static_cast(((value & 0x7FFF) << 16 | (value & 0xFFFF0000) >> 16) | sign_bit), bitmask); - result = static_cast(value); } break; case SensorValueType::U_QWORD: // Ignore bitmask for U_QWORD value = get_data(data, offset); - result = static_cast(value); break; - case SensorValueType::S_QWORD: // Ignore bitmask for S_QWORD value = get_data(data, offset); - result = static_cast(value); break; case SensorValueType::U_QWORD_R: // Ignore bitmask for U_QWORD @@ -568,32 +554,16 @@ float payload_to_float(const std::vector &data, SensorValueType sensor_ value = static_cast(value & 0xFFFF) << 48 | (value & 0xFFFF000000000000) >> 48 | static_cast(value & 0xFFFF0000) << 32 | (value & 0x0000FFFF00000000) >> 32 | static_cast(value & 0xFFFF00000000) << 16 | (value & 0x00000000FFFF0000) >> 16; - result = static_cast(value); break; - case SensorValueType::S_QWORD_R: // Ignore bitmask for S_QWORD value = get_data(data, offset); - result = static_cast(value); break; - case SensorValueType::FP32: - raw_to_float.raw = get_data(data, offset); - ESP_LOGD(TAG, "FP32 = 0x%08X => %f", raw_to_float.raw, raw_to_float.float_value); - result = raw_to_float.float_value; - break; - case SensorValueType::FP32_R: { - auto tmp = get_data(data, offset); - raw_to_float.raw = static_cast(tmp & 0xFFFF) << 16 | (tmp & 0xFFFF0000) >> 16; - ESP_LOGD(TAG, "FP32_R = 0x%08X => %f", raw_to_float.raw, raw_to_float.float_value); - result = raw_to_float.float_value; - } break; case SensorValueType::RAW: - result = NAN; - break; default: break; } - return result; + return value; } } // namespace modbus_controller diff --git a/esphome/components/modbus_controller/modbus_controller.h b/esphome/components/modbus_controller/modbus_controller.h index 88e2bba9ad..09395f29b3 100644 --- a/esphome/components/modbus_controller/modbus_controller.h +++ b/esphome/components/modbus_controller/modbus_controller.h @@ -195,7 +195,7 @@ inline bool coil_from_vector(int coil, const std::vector &data) { */ template N mask_and_shift_by_rightbit(N data, uint32_t mask) { auto result = (mask & data); - if (result == 0) { + if (result == 0 || mask == 0xFFFFFFFF) { return result; } for (size_t pos = 0; pos < sizeof(N) << 3; pos++) { @@ -205,22 +205,23 @@ template N mask_and_shift_by_rightbit(N data, uint32_t mask) { return 0; } -/** convert float value to vector suitable for sending - * @param value float value to cconvert +/** Convert float value to vector suitable for sending + * @param data target for payload + * @param value float value to convert * @param value_type defines if 16/32 or FP32 is used * @return vector containing the modbus register words in correct order */ -std::vector float_to_payload(float value, SensorValueType value_type); +void number_to_payload(std::vector &data, int64_t value, SensorValueType value_type); -/** convert vector response payload to float - * @param value float value to cconvert +/** Convert vector response payload to number. + * @param data payload with the data to convert * @param sensor_value_type defines if 16/32/64 bits or FP32 is used * @param offset offset to the data in data * @param bitmask bitmask used for masking and shifting - * @return float version of the input + * @return 64-bit number of the payload */ -float payload_to_float(const std::vector &data, SensorValueType sensor_value_type, uint8_t offset, - uint32_t bitmask); +int64_t payload_to_number(const std::vector &data, SensorValueType sensor_value_type, uint8_t offset, + uint32_t bitmask); class ModbusController; @@ -348,11 +349,11 @@ class ModbusCommandItem { * @param modbusdevice pointer to the device to execute the command * @param start_address modbus address of the first register to read * @param register_count number of registers to read - * @param values uint16_t array to be written to the registers + * @param value uint16_t single register value to write * @return ModbusCommandItem with the prepared command */ static ModbusCommandItem create_write_single_command(ModbusController *modbusdevice, uint16_t start_address, - int16_t value); + uint16_t value); /** Create modbus write single registers command * Function 05 (05hex) Write Single Coil * @param modbusdevice pointer to the device to execute the command @@ -446,13 +447,36 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice { uint16_t command_throttle_; }; -/** convert vector response payload to float - * @param value float value to cconvert +/** Convert vector response payload to float. + * @param data payload with data * @param item SensorItem object - * @return float version of the input + * @return float value of data */ inline float payload_to_float(const std::vector &data, const SensorItem &item) { - return payload_to_float(data, item.sensor_value_type, item.offset, item.bitmask); + int64_t number = payload_to_number(data, item.sensor_value_type, item.offset, item.bitmask); + + float float_value; + if (item.sensor_value_type == SensorValueType::FP32 || item.sensor_value_type == SensorValueType::FP32_R) { + float_value = bit_cast(static_cast(number)); + } else { + float_value = static_cast(number); + } + + return float_value; +} + +inline std::vector float_to_payload(float value, SensorValueType value_type) { + int64_t val; + + if (value_type == SensorValueType::FP32 || value_type == SensorValueType::FP32_R) { + val = bit_cast(value); + } else { + val = llroundf(value); + } + + std::vector data; + number_to_payload(data, val, value_type); + return data; } } // namespace modbus_controller diff --git a/esphome/components/modbus_controller/select/__init__.py b/esphome/components/modbus_controller/select/__init__.py new file mode 100644 index 0000000000..9651b5fedb --- /dev/null +++ b/esphome/components/modbus_controller/select/__init__.py @@ -0,0 +1,142 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import select +from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA +from esphome.jsonschema import jschema_composite + +from .. import ( + SENSOR_VALUE_TYPE, + TYPE_REGISTER_MAP, + ModbusController, + SensorItem, + modbus_controller_ns, +) +from ..const import ( + CONF_FORCE_NEW_RANGE, + CONF_MODBUS_CONTROLLER_ID, + CONF_REGISTER_COUNT, + CONF_SKIP_UPDATES, + CONF_USE_WRITE_MULTIPLE, + CONF_VALUE_TYPE, + CONF_WRITE_LAMBDA, +) + +DEPENDENCIES = ["modbus_controller"] +CODEOWNERS = ["@martgras", "@stegm"] +CONF_OPTIONSMAP = "optionsmap" + +ModbusSelect = modbus_controller_ns.class_( + "ModbusSelect", cg.Component, select.Select, SensorItem +) + + +@jschema_composite +def ensure_option_map(): + def validator(value): + cv.check_not_templatable(value) + option = cv.All(cv.string_strict) + mapping = cv.All(cv.int_range(-(2 ** 63), 2 ** 63 - 1)) + options_map_schema = cv.Schema({option: mapping}) + value = options_map_schema(value) + + all_values = list(value.values()) + unique_values = set(value.values()) + if len(all_values) != len(unique_values): + raise cv.Invalid("Mapping values must be unique.") + + return value + + return validator + + +def register_count_value_type_min(value): + reg_count = value.get(CONF_REGISTER_COUNT) + if reg_count is not None: + value_type = value[CONF_VALUE_TYPE] + min_register_count = TYPE_REGISTER_MAP[value_type] + if min_register_count > reg_count: + raise cv.Invalid( + f"Value type {value_type} needs at least {min_register_count} registers" + ) + return value + + +INTEGER_SENSOR_VALUE_TYPE = { + key: value for key, value in SENSOR_VALUE_TYPE.items() if not key.startswith("FP") +} + +CONFIG_SCHEMA = cv.All( + select.SELECT_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + { + cv.GenerateID(): cv.declare_id(ModbusSelect), + cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController), + cv.Required(CONF_ADDRESS): cv.positive_int, + cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum( + INTEGER_SENSOR_VALUE_TYPE + ), + cv.Optional(CONF_REGISTER_COUNT): cv.positive_int, + cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int, + cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean, + cv.Required(CONF_OPTIONSMAP): ensure_option_map(), + cv.Optional(CONF_USE_WRITE_MULTIPLE, default=False): cv.boolean, + cv.Optional(CONF_LAMBDA): cv.returning_lambda, + cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda, + }, + ), + register_count_value_type_min, +) + + +async def to_code(config): + value_type = config[CONF_VALUE_TYPE] + reg_count = config.get(CONF_REGISTER_COUNT) + if reg_count is None: + reg_count = TYPE_REGISTER_MAP[value_type] + + options_map = config[CONF_OPTIONSMAP] + + var = cg.new_Pvariable( + config[CONF_ID], + value_type, + config[CONF_ADDRESS], + reg_count, + config[CONF_SKIP_UPDATES], + config[CONF_FORCE_NEW_RANGE], + list(options_map.values()), + ) + + await cg.register_component(var, config) + await select.register_select(var, config, options=list(options_map.keys())) + + parent = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID]) + cg.add(parent.add_sensor_item(var)) + cg.add(var.set_parent(parent)) + cg.add(var.set_use_write_mutiple(config[CONF_USE_WRITE_MULTIPLE])) + + if CONF_LAMBDA in config: + template_ = await cg.process_lambda( + config[CONF_LAMBDA], + [ + (ModbusSelect.operator("const_ptr"), "item"), + (cg.int64, "x"), + ( + cg.std_vector.template(cg.uint8).operator("const").operator("ref"), + "data", + ), + ], + return_type=cg.optional.template(cg.std_string), + ) + cg.add(var.set_template(template_)) + + if CONF_WRITE_LAMBDA in config: + template_ = await cg.process_lambda( + config[CONF_WRITE_LAMBDA], + [ + (ModbusSelect.operator("const_ptr"), "item"), + (cg.std_string.operator("const").operator("ref"), "x"), + (cg.int64, "value"), + (cg.std_vector.template(cg.uint16).operator("ref"), "payload"), + ], + return_type=cg.optional.template(cg.int64), + ) + cg.add(var.set_write_template(template_)) diff --git a/esphome/components/modbus_controller/select/modbus_select.cpp b/esphome/components/modbus_controller/select/modbus_select.cpp new file mode 100644 index 0000000000..2c6b32f545 --- /dev/null +++ b/esphome/components/modbus_controller/select/modbus_select.cpp @@ -0,0 +1,86 @@ +#include "modbus_select.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace modbus_controller { + +static const char *const TAG = "modbus_controller.select"; + +void ModbusSelect::dump_config() { LOG_SELECT(TAG, "Modbus Controller Select", this); } + +void ModbusSelect::parse_and_publish(const std::vector &data) { + int64_t value = payload_to_number(data, this->sensor_value_type, this->offset, this->bitmask); + + ESP_LOGD(TAG, "New select value %lld from payload", value); + + optional new_state; + + if (this->transform_func_.has_value()) { + auto val = (*this->transform_func_)(this, value, data); + if (val.has_value()) { + new_state = *val; + ESP_LOGV(TAG, "lambda returned option %s", new_state->c_str()); + } + } + + if (!new_state.has_value()) { + auto map_it = std::find(this->mapping_.cbegin(), this->mapping_.cend(), value); + + if (map_it != this->mapping_.cend()) { + size_t idx = std::distance(this->mapping_.cbegin(), map_it); + new_state = this->traits.get_options()[idx]; + ESP_LOGV(TAG, "Found option %s for value %lld", new_state->c_str(), value); + } else { + ESP_LOGE(TAG, "No option found for mapping %lld", value); + } + } + + if (new_state.has_value()) { + this->publish_state(new_state.value()); + } +} + +void ModbusSelect::control(const std::string &value) { + auto options = this->traits.get_options(); + auto opt_it = std::find(options.cbegin(), options.cend(), value); + size_t idx = std::distance(options.cbegin(), opt_it); + optional mapval = this->mapping_[idx]; + ESP_LOGD(TAG, "Found value %lld for option '%s'", *mapval, value.c_str()); + + std::vector data; + + if (this->write_transform_func_.has_value()) { + auto val = (*this->write_transform_func_)(this, value, *mapval, data); + if (val.has_value()) { + mapval = *val; + ESP_LOGV(TAG, "write_lambda returned mapping value %lld", *mapval); + } else { + ESP_LOGD(TAG, "Communication handled by write_lambda - exiting control"); + return; + } + } + + if (data.empty()) { + number_to_payload(data, *mapval, this->sensor_value_type); + } else { + ESP_LOGV(TAG, "Using payload from write lambda"); + } + + if (data.empty()) { + ESP_LOGW(TAG, "No payload was created for updating select"); + return; + } + + const uint16_t write_address = this->start_address + this->offset / 2; + ModbusCommandItem write_cmd; + if ((this->register_count == 1) && (!this->use_write_multiple_)) { + write_cmd = ModbusCommandItem::create_write_single_command(parent_, write_address, data[0]); + } else { + write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, write_address, this->register_count, data); + } + + parent_->queue_command(write_cmd); +} + +} // namespace modbus_controller +} // namespace esphome diff --git a/esphome/components/modbus_controller/select/modbus_select.h b/esphome/components/modbus_controller/select/modbus_select.h new file mode 100644 index 0000000000..0875194768 --- /dev/null +++ b/esphome/components/modbus_controller/select/modbus_select.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include "esphome/components/modbus_controller/modbus_controller.h" +#include "esphome/components/select/select.h" +#include "esphome/core/component.h" + +namespace esphome { +namespace modbus_controller { + +class ModbusSelect : public Component, public select::Select, public SensorItem { + public: + ModbusSelect(SensorValueType sensor_value_type, uint16_t start_address, uint8_t register_count, uint8_t skip_updates, + bool force_new_range, std::vector mapping) { + this->register_type = ModbusRegisterType::HOLDING; // not configurable + this->sensor_value_type = sensor_value_type; + this->start_address = start_address; + this->offset = 0; // not configurable + this->bitmask = 0xFFFFFFFF; // not configurable + this->register_count = register_count; + this->response_bytes = 0; // not configurable + this->skip_updates = skip_updates; + this->force_new_range = force_new_range; + this->mapping_ = std::move(mapping); + } + + using transform_func_t = + std::function(ModbusSelect *const, int64_t, const std::vector &)>; + using write_transform_func_t = + std::function(ModbusSelect *const, const std::string &, int64_t, std::vector &)>; + + void set_parent(ModbusController *const parent) { this->parent_ = parent; } + void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; } + void set_template(transform_func_t &&f) { this->transform_func_ = f; } + void set_write_template(write_transform_func_t &&f) { this->write_transform_func_ = f; } + + void dump_config() override; + void parse_and_publish(const std::vector &data) override; + void control(const std::string &value) override; + + protected: + std::vector mapping_; + ModbusController *parent_; + bool use_write_multiple_{false}; + optional transform_func_; + optional write_transform_func_; +}; + +} // namespace modbus_controller +} // namespace esphome diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 937b6cceb4..82deec70ec 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -773,9 +773,11 @@ class MockObj(Expression): return MockObj(f"{self.base} &", "") if name == "ptr": return MockObj(f"{self.base} *", "") + if name == "const_ptr": + return MockObj(f"{self.base} *const", "") if name == "const": return MockObj(f"const {self.base}", "") - raise ValueError("Expected one of ref, ptr, const.") + raise ValueError("Expected one of ref, ptr, const_ptr, const.") @property def using(self) -> "MockObj": diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py index 110641d6c9..2323b2578f 100644 --- a/esphome/cpp_types.py +++ b/esphome/cpp_types.py @@ -15,6 +15,7 @@ uint16 = global_ns.namespace("uint16_t") uint32 = global_ns.namespace("uint32_t") uint64 = global_ns.namespace("uint64_t") int32 = global_ns.namespace("int32_t") +int64 = global_ns.namespace("int64_t") const_char_ptr = global_ns.namespace("const char *") NAN = global_ns.namespace("NAN") esphome_ns = global_ns # using namespace esphome;