@@ -236,7 +236,8 @@ function generateSnippetLocally() {
236236
237237 // 6. Sensors (Battery, SHT4x, etc + Widget Sensors)
238238 const widgetSensorLines = [ ] ;
239- const processedSensorIds = new Set ( ) ; // Prevent duplicates
239+ const processedSensorIds = new Set ( ) ; // For numeric sensors
240+ const processedTextSensorEntities = new Set ( ) ; // For text sensors
240241 const haTextSensorLines = [ ] ; // For text_sensor HA imports
241242
242243 pagesLocal . forEach ( p => {
@@ -253,42 +254,57 @@ function generateSnippetLocally() {
253254 const isLocal = ! ! props . is_local_sensor ;
254255
255256 // Only import HA entities, not local ones
256- if ( entity && ! isLocal && ! processedSensorIds . has ( entity ) ) {
257- processedSensorIds . add ( entity ) ;
257+ if ( entity && ! isLocal ) {
258258 const entityId = entity . replace ( / [ ^ a - z A - Z 0 - 9 _ ] / g, "_" ) ;
259259
260260 if ( isTextSensor || entity . startsWith ( "text_sensor." ) ) {
261- haTextSensorLines . push ( ` - platform: homeassistant` ) ;
262- haTextSensorLines . push ( ` id: ${ entityId } ` ) ;
263- haTextSensorLines . push ( ` entity_id: ${ entity } ` ) ;
264- haTextSensorLines . push ( ` internal: true` ) ;
261+ // Text Sensor Mode: Use specific ID and allow parallel registration
262+ if ( ! processedTextSensorEntities . has ( entity ) ) {
263+ processedTextSensorEntities . add ( entity ) ;
264+ haTextSensorLines . push ( ` - platform: homeassistant` ) ;
265+ haTextSensorLines . push ( ` id: ${ entityId } _txt` ) ;
266+ haTextSensorLines . push ( ` entity_id: ${ entity } ` ) ;
267+ haTextSensorLines . push ( ` internal: true` ) ;
268+ }
265269 } else {
266- widgetSensorLines . push ( ` - platform: homeassistant` ) ;
267- widgetSensorLines . push ( ` id: ${ entityId } ` ) ;
268- widgetSensorLines . push ( ` entity_id: ${ entity } ` ) ;
269- widgetSensorLines . push ( ` internal: true` ) ;
270+ // Numeric Sensor Mode: Use standard ID and checks
271+ if ( ! processedSensorIds . has ( entity ) ) {
272+ processedSensorIds . add ( entity ) ;
273+ widgetSensorLines . push ( ` - platform: homeassistant` ) ;
274+ widgetSensorLines . push ( ` id: ${ entityId } ` ) ;
275+ widgetSensorLines . push ( ` entity_id: ${ entity } ` ) ;
276+ widgetSensorLines . push ( ` internal: true` ) ;
277+ }
270278 }
271279 }
272280
273281 // Handle secondary entity
274- if ( entity2 && ! isLocal && ! processedSensorIds . has ( entity2 ) ) {
275- processedSensorIds . add ( entity2 ) ;
282+ if ( entity2 && ! isLocal ) {
276283 const entityId2 = entity2 . replace ( / [ ^ a - z A - Z 0 - 9 _ ] / g, "_" ) ;
277284
278285 if ( isTextSensor || entity2 . startsWith ( "text_sensor." ) ) {
279- haTextSensorLines . push ( ` - platform: homeassistant` ) ;
280- haTextSensorLines . push ( ` id: ${ entityId2 } ` ) ;
281- haTextSensorLines . push ( ` entity_id: ${ entity2 } ` ) ;
282- haTextSensorLines . push ( ` internal: true` ) ;
286+ if ( ! processedTextSensorEntities . has ( entity2 ) ) {
287+ processedTextSensorEntities . add ( entity2 ) ;
288+ haTextSensorLines . push ( ` - platform: homeassistant` ) ;
289+ haTextSensorLines . push ( ` id: ${ entityId2 } _txt` ) ;
290+ haTextSensorLines . push ( ` entity_id: ${ entity2 } ` ) ;
291+ haTextSensorLines . push ( ` internal: true` ) ;
292+ }
283293 } else {
284- widgetSensorLines . push ( ` - platform: homeassistant` ) ;
285- widgetSensorLines . push ( ` id: ${ entityId2 } ` ) ;
286- widgetSensorLines . push ( ` entity_id: ${ entity2 } ` ) ;
287- widgetSensorLines . push ( ` internal: true` ) ;
294+ if ( ! processedSensorIds . has ( entity2 ) ) {
295+ processedSensorIds . add ( entity2 ) ;
296+ widgetSensorLines . push ( ` - platform: homeassistant` ) ;
297+ widgetSensorLines . push ( ` id: ${ entityId2 } ` ) ;
298+ widgetSensorLines . push ( ` entity_id: ${ entity2 } ` ) ;
299+ widgetSensorLines . push ( ` internal: true` ) ;
300+ }
288301 }
289302 }
290303 }
291304
305+
306+
307+
292308 // Also collect graph widget entities
293309 if ( t === "graph" ) {
294310 const entity = w . entity_id || "" ;
@@ -555,8 +571,8 @@ function generateSnippetLocally() {
555571
556572 // Collect weather entities used by sensor_text and weather_icon widgets
557573 const weatherEntitiesUsed = new Set ( ) ;
558- // Collect text_sensor entities used by sensor_text widgets
559- const textSensorEntitiesUsed = new Set ( ) ;
574+ // (Redundant textSensorEntitiesUsed logic removed)
575+
560576 for ( const page of pagesLocal ) {
561577 if ( ! page || ! Array . isArray ( page . widgets ) ) continue ;
562578 for ( const w of page . widgets ) {
@@ -567,18 +583,11 @@ function generateSnippetLocally() {
567583 if ( ( t === "sensor_text" || t === "weather_icon" ) && entityId . startsWith ( "weather." ) ) {
568584 weatherEntitiesUsed . add ( entityId ) ;
569585 }
570- if ( t === "sensor_text" && entityId . startsWith ( "text_sensor." ) ) {
571- textSensorEntitiesUsed . add ( entityId ) ;
572- }
573- // Also add sensor.* entities marked as text sensors to the text_sensor block
574- if ( t === "sensor_text" && entityId . startsWith ( "sensor." ) && p . is_text_sensor ) {
575- textSensorEntitiesUsed . add ( entityId ) ;
576- }
577586 }
578587 }
579588
580- // Check if we need text_sensor block
581- const needsTextSensors = quoteRssWidgets . length > 0 || weatherForecastWidgets . length > 0 || weatherEntitiesUsed . size > 0 || textSensorEntitiesUsed . size > 0 || calendarWidgets . length > 0 ;
589+ // Check if we need text_sensor block (secondary block for extras)
590+ const needsTextSensors = quoteRssWidgets . length > 0 || weatherForecastWidgets . length > 0 || weatherEntitiesUsed . size > 0 || calendarWidgets . length > 0 ;
582591
583592 if ( needsTextSensors ) {
584593 lines . push ( "text_sensor:" ) ;
@@ -622,20 +631,6 @@ function generateSnippetLocally() {
622631 lines . push ( "" ) ;
623632 }
624633
625- // Add text_sensor entity sensors (for sensor_text widgets using text_sensor.* or sensor.* entities marked as text sensors)
626- if ( textSensorEntitiesUsed . size > 0 ) {
627- lines . push ( " # Text Sensor Entity Sensors (from Home Assistant)" ) ;
628- for ( const entityId of textSensorEntitiesUsed ) {
629- // Handle both text_sensor.* and sensor.* prefixes
630- const safeId = entityId . replace ( / ^ ( t e x t _ s e n s o r | s e n s o r ) \. / , "" ) . replace ( / \. / g, "_" ) . replace ( / - / g, "_" ) ;
631- lines . push ( ` - platform: homeassistant` ) ;
632- lines . push ( ` id: ${ safeId } ` ) ;
633- lines . push ( ` entity_id: ${ entityId } ` ) ;
634- lines . push ( ` internal: true` ) ;
635- }
636- lines . push ( "" ) ;
637- }
638-
639634 // Add weather forecast condition sensors
640635 if ( weatherForecastWidgets . length > 0 ) {
641636 lines . push ( " # Weather Forecast Condition Sensors" ) ;
@@ -1040,7 +1035,8 @@ function generateSnippetLocally() {
10401035 const weight = parseInt ( p . font_weight || 400 ) ;
10411036 const italic = ! ! p . italic ;
10421037 const valueFormat = p . value_format || "label_value" ;
1043- const precision = parseInt ( p . precision , 10 ) ;
1038+ let precision = parseInt ( p . precision , 10 ) ;
1039+ if ( isNaN ( precision ) ) precision = 2 ; // Default to 2 decimals if not set
10441040 const prefix = ( p . prefix || "" ) . replace ( / " / g, '\\"' ) ;
10451041 const postfix = ( p . postfix || "" ) . replace ( / " / g, '\\"' ) ;
10461042 const unit = ( p . unit || "" ) . replace ( / " / g, '\\"' ) ;
@@ -1063,7 +1059,7 @@ function generateSnippetLocally() {
10631059 const valueFontId = addFont ( family , weight , valueFontSize , italic ) ;
10641060
10651061 // Widget metadata comment - include all properties for round-trip persistence
1066- lines . push ( ` // widget:sensor_text id:${ w . id } type:sensor_text x:${ w . x } y:${ w . y } w:${ w . width } h:${ w . height } ent:${ entity } entity_2:${ entity2 } title:"${ title } " format:${ valueFormat } label_font:${ labelFontSize } value_font:${ valueFontSize } color:${ colorProp } label_align:${ align } value_align:${ align } precision:${ isNaN ( precision ) ? - 1 : precision } unit:"${ unit } " prefix:"${ prefix } " postfix:"${ postfix } " separator:"${ separator } " local:${ isLocalSensor } text_sensor:${ isTextSensor } font_family:"${ family } " font_weight:${ weight } italic:${ italic } ` ) ;
1062+ lines . push ( ` // widget:sensor_text id:${ w . id } type:sensor_text x:${ w . x } y:${ w . y } w:${ w . width } h:${ w . height } ent:${ entity } entity_2:${ entity2 } title:"${ title } " format:${ valueFormat } label_font:${ labelFontSize } value_font:${ valueFontSize } color:${ colorProp } label_align:${ align } value_align:${ align } precision:${ precision } unit:"${ unit } " prefix:"${ prefix } " postfix:"${ postfix } " separator:"${ separator } " local:${ isLocalSensor } text_sensor:${ isTextSensor } font_family:"${ family } " font_weight:${ weight } italic:${ italic } ` ) ;
10671063
10681064 if ( ! entity ) {
10691065 lines . push ( ` it.printf(${ w . x } , ${ w . y } , id(${ valueFontId } ), ${ color } , TextAlign::TOP_LEFT, "No Entity");` ) ;
@@ -1077,7 +1073,7 @@ function generateSnippetLocally() {
10771073
10781074 // Get value as string - handle text sensors vs numeric sensors
10791075 if ( isTextSensor || entity . startsWith ( "text_sensor." ) ) {
1080- lines . push ( ` std::string val1 = id(${ entityId } ).state;` ) ;
1076+ lines . push ( ` std::string val1 = id(${ entityId } _txt ).state;` ) ;
10811077 } else {
10821078 // Numeric sensor with optional precision
10831079 if ( ! isNaN ( precision ) && precision >= 0 ) {
@@ -1091,8 +1087,8 @@ function generateSnippetLocally() {
10911087
10921088 // Handle secondary entity if present
10931089 if ( entityId2 ) {
1094- if ( isTextSensor ) {
1095- lines . push ( ` std::string val2 = id(${ entityId2 } ).state;` ) ;
1090+ if ( isTextSensor || ( entity2 && entity2 . startsWith ( "text_sensor." ) ) ) {
1091+ lines . push ( ` std::string val2 = id(${ entityId2 } _txt ).state;` ) ;
10961092 } else {
10971093 if ( ! isNaN ( precision ) && precision >= 0 ) {
10981094 lines . push ( ` char buf2[32];` ) ;
0 commit comments