When are sensor templates updated if they're recursive? Am I creating a loop?

I have a sensor that’s pulling luminance levels from an actual light sensor. I previously had this working fine as an input_number, but switched it over to try it as a sensor template named sensor.mud_room_lux since I don’t want the slider showing up in the interface. The thing is I don’t want the template sensor to update when one of the lights is on in the room (light.m_ceiling); if the light is on, the sensor template should retain its previous value. Here is the sensor template:

- platform: template
  sensors:      
    mud_room_lux:
      friendly_name: "Non-lit Mud Moom Lux"
      unit_of_measurement: "lux"
      value_template: >-
        {% if is_state('light.m_ceiling', 'off') %}
          {{ states('sensor.mud_room_sensor_luminance') }}
        {% else %}
          {{ states('sensor.mud_room_lux') }}
        {% endif %}

I’m not sure what to put in the else stanza; if I leave it off the value is updated whether light.m_ceiling is on or off. I’m guessing this is because it’s evaluating to false, but falling through without any value assigned, so it does it anyway. If I put in the else statement as above it works correctly, but I’m worried about weird loops or race conditions, as it’s evaluating itself recursively, and causing unnecessary load. The load doesn’t seem to be affected, but I’m not sure if this is optimal.

The reason for this ambiguity is because it’s not clear in the docs when the sensor template evaluation is taking place. On a normal template sensor with a value derived from a state attribute, this likely occurs on a state change of the actual source entity attribute, but here, in the situation where the light is on, leads the template sensor itself to be both the source and the target.

Can anyone clear up when template sensors are evaluated in the case of self-referencing conditionals?

That probably will create problems. Just make it only update when the ceiling fan is ‘off’…

- platform: template
  sensors:      
    mud_room_lux:
      friendly_name: "Non-lit Mud Moom Lux"
      unit_of_measurement: "lux"
      value_template: >-
        {% if is_state('light.m_ceiling', 'off') %}
          {{ states('sensor.mud_room_sensor_luminance') }}
        {% endif %}

If that causes issues when the light is on, just switch back to your input_number and hide the item in customize.

customize:
  my_item:
    hidden: True

Yeah when I do the value template without and else stanza, I’ve run into some odd behavior; I’ll have to test it so see what it’s doing.

I did end up coming to the same conclusion as you and using input_number as a variable to store the current luminance value if the light’s off:
(in an automations section):

- alias: "Determine non-lit lux level"
  trigger:
    - platform: state
      entity_id: sensor.mud_room_sensor_luminance
  condition:
    condition: state
    entity_id: light.m_ceiling
    state: "off"
  action:
    service: input_number.set_value
    entity_id: input_number.mud_room_lux
    data_template:
      value: "{{ states('sensor.mud_room_sensor_luminance') }}"

Then just converting that into a sensor:

- platform: template
  sensors:
    mud_room_lux:
      friendly_name: "Non-lit Mud Moom Lux"
      unit_of_measurement: "lux"
      value_template: "{{ states('input_number.mud_room_lux') }}"

It seems more readable to put the logic into an input_number acting as a variable and leaving it out of any views, then pulling the result into a sensor, even if it’s a bit of a roundabout way.