Skip to content

Commit 8b6a66e

Browse files
committed
Include attributes in generated text sensors
Handle entity attributes when generating text/weather Home Assistant sensors. makeSafeId now accepts an attribute and uses it when building the base ID; entity sets (weatherEntities/textEntities) store {entity_id, attribute} so duplicates are tracked per-attribute; seenTextEntityIds uniqueness now includes attribute; generated sensor blocks include an attribute field when present. This prevents ID/key collisions and ensures attribute-based text sensors are created correctly.
1 parent 2971f72 commit 8b6a66e

File tree

1 file changed

+34
-14
lines changed
  • custom_components/esphome_designer/frontend/features/sensor_text

1 file changed

+34
-14
lines changed

custom_components/esphome_designer/frontend/features/sensor_text/plugin.js

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -896,8 +896,10 @@ export default {
896896
};
897897

898898
// Helper to create safe ESPHome ID (max 59 chars before suffix)
899-
const makeSafeId = (eid, suffix = "") => {
900-
let safe = eid.replace(/[^a-zA-Z0-9_]/g, "_");
899+
// Helper to create safe ESPHome ID (max 59 chars before suffix)
900+
const makeSafeId = (eid, attr, suffix = "") => {
901+
const base = attr ? (eid + "_" + attr) : eid;
902+
let safe = base.replace(/[^a-zA-Z0-9_]/g, "_");
901903
const maxBase = 63 - suffix.length;
902904
if (safe.length > maxBase) safe = safe.substring(0, maxBase);
903905
return safe + suffix;
@@ -914,66 +916,84 @@ export default {
914916

915917
// Auto-detect: check if entity has non-numeric state (like "pm25")
916918
const isAutoText = !p.is_local_sensor && isEntityStateNonNumeric(entityId);
919+
const attribute = (p.attribute || "").trim();
917920

918921
if (entityId.startsWith("weather.")) {
919-
weatherEntities.add(entityId);
922+
weatherEntities.add(JSON.stringify({ entity_id: entityId, attribute }));
920923
} else if (p.is_text_sensor || isAutoText || entityId.startsWith("text_sensor.")) {
921-
textEntities.add(entityId);
924+
textEntities.add(JSON.stringify({ entity_id: entityId, attribute }));
922925
}
923926

924927
const entityId2 = (w.entity_id_2 || p.entity_id_2 || "").trim();
925928
if (entityId2) {
926929
const isAutoText2 = !p.is_local_sensor && isEntityStateNonNumeric(entityId2);
927930
if (entityId2.startsWith("weather.")) {
928-
weatherEntities.add(entityId2);
931+
weatherEntities.add(JSON.stringify({ entity_id: entityId2, attribute: "" }));
929932
} else if (p.is_text_sensor || isAutoText2 || entityId2.startsWith("text_sensor.")) {
930-
textEntities.add(entityId2);
933+
textEntities.add(JSON.stringify({ entity_id: entityId2, attribute: "" }));
931934
}
932935
}
933936
}
934937

935938
if (weatherEntities.size > 0) {
936939
let headerAdded = false;
937-
for (let entityId of weatherEntities) {
940+
for (let json of weatherEntities) {
941+
const { entity_id: rawId, attribute } = JSON.parse(json);
942+
let entityId = rawId;
943+
938944
if (entityId && !entityId.includes(".")) entityId = `weather.${entityId}`;
939-
const safeId = makeSafeId(entityId, "_txt");
945+
const safeId = makeSafeId(entityId, attribute, "_txt");
946+
940947
if (context.seenSensorIds && context.seenSensorIds.has(safeId)) continue;
941-
if (context.seenTextEntityIds && context.seenTextEntityIds.has(entityId)) continue;
948+
// Unique key includes attribute now
949+
const entityKey = attribute ? `${entityId}__attr__${attribute}` : entityId;
950+
if (context.seenTextEntityIds && context.seenTextEntityIds.has(entityKey)) continue;
942951

943952
if (!headerAdded) {
944953
lines.push("# Weather Entity Sensors (Detected from Sensor Text)");
945954
headerAdded = true;
946955
}
947956

948957
if (context.seenSensorIds) context.seenSensorIds.add(safeId);
949-
if (context.seenTextEntityIds) context.seenTextEntityIds.add(entityId);
958+
if (context.seenTextEntityIds) context.seenTextEntityIds.add(entityKey);
950959

951960
lines.push("- platform: homeassistant");
952961
lines.push(` id: ${safeId}`);
953962
lines.push(` entity_id: ${entityId}`);
963+
if (attribute) {
964+
lines.push(` attribute: ${attribute}`);
965+
}
954966
lines.push(` internal: true`);
955967
}
956968
}
957969

958970
if (textEntities.size > 0) {
959971
let headerAdded = false;
960-
for (let entityId of textEntities) {
972+
for (let json of textEntities) {
973+
const { entity_id: entityId, attribute } = JSON.parse(json);
974+
961975
// Don't add text_sensor prefix to sensor.* entities - just register them as text sensors
962-
const safeId = makeSafeId(entityId, "_txt");
976+
const safeId = makeSafeId(entityId, attribute, "_txt");
977+
963978
if (context.seenSensorIds && context.seenSensorIds.has(safeId)) continue;
964-
if (context.seenTextEntityIds && context.seenTextEntityIds.has(entityId)) continue;
979+
980+
const entityKey = attribute ? `${entityId}__attr__${attribute}` : entityId;
981+
if (context.seenTextEntityIds && context.seenTextEntityIds.has(entityKey)) continue;
965982

966983
if (!headerAdded) {
967984
lines.push("# Text Sensors (Detected from Sensor Text)");
968985
headerAdded = true;
969986
}
970987

971988
if (context.seenSensorIds) context.seenSensorIds.add(safeId);
972-
if (context.seenTextEntityIds) context.seenTextEntityIds.add(entityId);
989+
if (context.seenTextEntityIds) context.seenTextEntityIds.add(entityKey);
973990

974991
lines.push("- platform: homeassistant");
975992
lines.push(` id: ${safeId}`);
976993
lines.push(` entity_id: ${entityId}`);
994+
if (attribute) {
995+
lines.push(` attribute: ${attribute}`);
996+
}
977997
lines.push(` internal: true`);
978998
}
979999
}

0 commit comments

Comments
 (0)