diff --git a/esphome/components/mapping/__init__.py b/esphome/components/mapping/__init__.py index 79657084fa..94c7c10a82 100644 --- a/esphome/components/mapping/__init__.py +++ b/esphome/components/mapping/__init__.py @@ -10,7 +10,8 @@ from esphome.loader import get_component CODEOWNERS = ["@clydebarrow"] MULTI_CONF = True -map_ = cg.std_ns.class_("map") +mapping_ns = cg.esphome_ns.namespace("mapping") +mapping_class = mapping_ns.class_("Mapping") CONF_ENTRIES = "entries" CONF_CLASS = "class" @@ -29,7 +30,11 @@ class IndexType: INDEX_TYPES = { "int": IndexType(cv.int_, cg.int_, int), - "string": IndexType(cv.string, cg.std_string, str), + "string": IndexType( + cv.string, + cg.std_string, + str, + ), } @@ -47,7 +52,7 @@ def to_schema(value): BASE_SCHEMA = cv.Schema( { - cv.Required(CONF_ID): cv.declare_id(map_), + cv.Required(CONF_ID): cv.declare_id(mapping_class), cv.Required(CONF_FROM): cv.one_of(*INDEX_TYPES, lower=True), cv.Required(CONF_TO): cv.string, }, @@ -123,12 +128,15 @@ async def to_code(config): if list(entries.values())[0].op != ".": value_type = value_type.operator("ptr") varid = config[CONF_ID] - varid.type = map_.template(index_type, value_type) + varid.type = mapping_class.template( + index_type, + value_type, + ) var = MockObj(varid, ".") decl = VariableDeclarationExpression(varid.type, "", varid) add_global(decl) CORE.register_variable(varid, var) for key, value in entries.items(): - cg.add(var.insert((key, value))) + cg.add(var.set(key, value)) return var diff --git a/esphome/components/mapping/mapping.h b/esphome/components/mapping/mapping.h new file mode 100644 index 0000000000..99c1f38829 --- /dev/null +++ b/esphome/components/mapping/mapping.h @@ -0,0 +1,69 @@ +#pragma once + +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include +#include + +namespace esphome::mapping { + +using alloc_string_t = std::basic_string, RAMAllocator>; + +/** + * + * Mapping class with custom allocator. + * Additionally, when std::string is used as key or value, it will be replaced with a custom string type + * that uses RAMAllocator. + * @tparam K The type of the key in the mapping. + * @tparam V The type of the value in the mapping. Should be a basic type or pointer. + */ + +static const char *const TAG = "mapping"; + +template class Mapping { + public: + // Constructor + Mapping() = default; + + using key_t = const std::conditional_t, + alloc_string_t, // if K is std::string, custom string type + K>; + using value_t = std::conditional_t, + alloc_string_t, // if V is std::string, custom string type + V>; + + void set(const K &key, const V &value) { this->map_[key_t{key}] = value; } + + V get(const K &key) const { + auto it = this->map_.find(key_t{key}); + if (it != this->map_.end()) { + return V{it->second}; + } + if constexpr (std::is_pointer_v) { + esph_log_e(TAG, "Key '%p' not found in mapping", key); + } else if constexpr (std::is_same_v) { + esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str()); + } else { + esph_log_e(TAG, "Key '%s' not found in mapping", to_string(key).c_str()); + } + return {}; + } + + // index map overload + V operator[](K key) { return this->get(key); } + + // convenience function for strings to get a C-style string + template, int> = 0> + const char *operator[](K key) const { + auto it = this->map_.find(key_t{key}); + if (it != this->map_.end()) { + return it->second.c_str(); // safe since value remains in map + } + return ""; + } + + protected: + std::map, RAMAllocator>> map_; +}; + +} // namespace esphome::mapping diff --git a/tests/components/mapping/.gitattributes b/tests/components/mapping/.gitattributes new file mode 100644 index 0000000000..9d74867fcf --- /dev/null +++ b/tests/components/mapping/.gitattributes @@ -0,0 +1 @@ +*.ttf -text diff --git a/tests/components/mapping/common.yaml b/tests/components/mapping/common.yaml index 07ca458146..7ffcfa4f67 100644 --- a/tests/components/mapping/common.yaml +++ b/tests/components/mapping/common.yaml @@ -50,6 +50,14 @@ mapping: red: red_id blue: blue_id green: green_id + - id: string_map_2 + from: string + to: string + entries: + one: "one" + two: "two" + three: "three" + seventy-seven: "seventy-seven" color: - id: red_id @@ -65,7 +73,14 @@ color: green: 0.0 blue: 1.0 +font: + - file: "$component_dir/helvetica.ttf" + id: font_id + size: 20 + display: lambda: |- - it.image(0, 0, id(weather_map)[0]); - it.image(0, 100, id(weather_map)[1]); + std::string value = id(int_map)[2]; + it.print(0, 0, id(font_id), TextAlign::TOP_LEFT, value.c_str()); + it.image(0, 0, id(weather_map)["clear-night"]); + it.image(0, 100, id(weather_map)["sunny"]); diff --git a/tests/components/mapping/helvetica.ttf b/tests/components/mapping/helvetica.ttf new file mode 100644 index 0000000000..7aec6f3f3c Binary files /dev/null and b/tests/components/mapping/helvetica.ttf differ diff --git a/tests/components/mapping/test.esp32-ard.yaml b/tests/components/mapping/test.esp32-ard.yaml index 951a6061f6..a76bf9349b 100644 --- a/tests/components/mapping/test.esp32-ard.yaml +++ b/tests/components/mapping/test.esp32-ard.yaml @@ -4,14 +4,14 @@ spi: mosi_pin: 17 miso_pin: 15 -display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 12 - dc_pin: 13 - reset_pin: 21 - invert_colors: false - packages: map: !include common.yaml + +display: + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + invert_colors: false diff --git a/tests/components/mapping/test.esp32-c3-ard.yaml b/tests/components/mapping/test.esp32-c3-ard.yaml index 55e5719e50..f95dd4f30d 100644 --- a/tests/components/mapping/test.esp32-c3-ard.yaml +++ b/tests/components/mapping/test.esp32-c3-ard.yaml @@ -5,13 +5,13 @@ spi: miso_pin: 5 display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 8 - dc_pin: 9 - reset_pin: 10 - invert_colors: false + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + invert_colors: false packages: map: !include common.yaml diff --git a/tests/components/mapping/test.esp32-c3-idf.yaml b/tests/components/mapping/test.esp32-c3-idf.yaml index 55e5719e50..f95dd4f30d 100644 --- a/tests/components/mapping/test.esp32-c3-idf.yaml +++ b/tests/components/mapping/test.esp32-c3-idf.yaml @@ -5,13 +5,13 @@ spi: miso_pin: 5 display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 8 - dc_pin: 9 - reset_pin: 10 - invert_colors: false + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 8 + dc_pin: 9 + reset_pin: 10 + invert_colors: false packages: map: !include common.yaml diff --git a/tests/components/mapping/test.esp32-idf.yaml b/tests/components/mapping/test.esp32-idf.yaml index 951a6061f6..231fdae797 100644 --- a/tests/components/mapping/test.esp32-idf.yaml +++ b/tests/components/mapping/test.esp32-idf.yaml @@ -5,13 +5,13 @@ spi: miso_pin: 15 display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 12 - dc_pin: 13 - reset_pin: 21 - invert_colors: false + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 12 + dc_pin: 13 + reset_pin: 21 + invert_colors: false packages: map: !include common.yaml diff --git a/tests/components/mapping/test.esp8266-ard.yaml b/tests/components/mapping/test.esp8266-ard.yaml index dd4642b8fe..a5b45d391a 100644 --- a/tests/components/mapping/test.esp8266-ard.yaml +++ b/tests/components/mapping/test.esp8266-ard.yaml @@ -5,13 +5,13 @@ spi: miso_pin: 12 display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 5 - dc_pin: 15 - reset_pin: 16 - invert_colors: false + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 5 + dc_pin: 15 + reset_pin: 16 + invert_colors: false packages: map: !include common.yaml diff --git a/tests/components/mapping/test.host.yaml b/tests/components/mapping/test.host.yaml index 98406767a4..19937e1f21 100644 --- a/tests/components/mapping/test.host.yaml +++ b/tests/components/mapping/test.host.yaml @@ -1,12 +1,12 @@ display: - - platform: sdl - id: sdl_display - update_interval: 1s - auto_clear_enabled: false - show_test_card: true - dimensions: - width: 450 - height: 600 + platform: sdl + id: sdl_display + update_interval: 1s + auto_clear_enabled: false + show_test_card: true + dimensions: + width: 450 + height: 600 packages: map: !include common.yaml diff --git a/tests/components/mapping/test.rp2040-ard.yaml b/tests/components/mapping/test.rp2040-ard.yaml index 1b7e796246..f092686553 100644 --- a/tests/components/mapping/test.rp2040-ard.yaml +++ b/tests/components/mapping/test.rp2040-ard.yaml @@ -5,13 +5,13 @@ spi: miso_pin: 4 display: - - platform: ili9xxx - id: main_lcd - model: ili9342 - cs_pin: 20 - dc_pin: 21 - reset_pin: 22 - invert_colors: false + platform: ili9xxx + id: main_lcd + model: ili9342 + cs_pin: 20 + dc_pin: 21 + reset_pin: 22 + invert_colors: false packages: map: !include common.yaml