Researched from current Home Assistant documentation on November 3, 2026. The timeline and YAML are worked examples, not measurements from a Tara installation or hardware tests. The cover is an AI-generated illustration. Menu labels can differ by release.

A weekly plan can hold more than on and off

The Home Assistant Schedule helper can supply different settings throughout a day. For a reading lamp, our recommendation is two blocks with different brightness percentages, one automation that reads the active setting, and a separate pause switch. Start with the notification-only version below.

A helper is a saved value or control inside Home Assistant. An entity is its named entry, such as schedule.reading_lamp_plan. An attribute is extra information attached to that entry. Here, the schedule’s on/off state tells us whether a block is active, and its brightness attribute tells us the setting to request.

This example deliberately treats a gap as “lamp off.” That is our chosen household rule, not an instruction built into every schedule. It suits a decorative reading lamp; do not adapt it to heating, medical equipment or other essential loads. The dedicated heating schedule guide explains thermostat-specific controls.

1. Write down the settings and the gaps

For this example, use the following plan on whichever weekdays you want it. Leave other days empty only if you want the lamp off throughout those days while this routine is enabled.

Illustrative plan. On a phone, scroll the table sideways.

TimeAdditional dataIntended result
16:00–20:00brightness_pct: 70Reading light at 70%
20:00–22:30brightness_pct: 25Lower evening light at 25%
Outside those blocksNo active blockLamp off

At 20:00 the schedule remains on, but its data changes from 70 to 25. At 22:30 it becomes off. The Schedule documentation confirms that touching blocks do not create an off/on interruption; overlapping blocks are not allowed.

Use percentages consistently. The light action distinguishes brightness_pct (0–100) from brightness (0–255). This example accepts whole percentages from 1–100 in an active block and uses a gap for off. A smart plug that only switches a lamp on and off cannot provide these dimming levels.

2. Create the plan and its pause switch

  1. Open Settings → Devices & services → Helpers → Create helper → Schedule. Name it Reading lamp plan.
  2. Draw the two blocks on one day. Open each block and enter its matching line from the table in Additional data. Repeat for the desired weekdays, then save.
  3. Create a Toggle helper named Reading lamp schedule enabled. Leave it off during setup.
  4. Check the helpers’ entity IDs. The code expects schedule.reading_lamp_plan and input_boolean.reading_lamp_schedule_enabled. Replace those names everywhere if yours differ.

The Toggle helper stores the pause choice and normally restores it after a restart. Put it on a dashboard the household uses, alongside the lamp’s ordinary control. Turning this toggle off pauses future commands; it does not itself turn the lamp off.

These steps create a UI-managed schedule. If you instead created one in configuration.yaml, edit that file and reload schedules; YAML-created schedules cannot be edited in the weekly UI. You do not need HACS or a custom scheduler for this walkthrough.

3. Add a notification-only preview

Under Settings → Automations & scenes, create an empty automation. Open its menu, select Edit in YAML, and replace the empty automation with the following. This is one complete automation, not a configuration.yaml entry. Save it and leave the automation itself enabled.

alias: Reading lamp schedule preview
triggers:
  - trigger: state
    entity_id: schedule.reading_lamp_plan
  - trigger: homeassistant
    event: start
  - trigger: state
    entity_id: input_boolean.reading_lamp_schedule_enabled
    to: "on"
conditions: []
actions:
  - condition: state
    entity_id: input_boolean.reading_lamp_schedule_enabled
    state: "on"
  - variables:
      plan_state: "{{ states('schedule.reading_lamp_plan') }}"
      level: "{{ state_attr('schedule.reading_lamp_plan', 'brightness_pct') }}"
  - condition: template
    value_template: >-
      {{ plan_state == 'off' or
         (plan_state == 'on' and level is not boolean and is_number(level)
          and (level | float(0)) == (level | int(0))
          and 1 <= (level | int(0)) <= 100) }}
  - action: persistent_notification.create
    data:
      notification_id: reading_lamp_schedule_preview
      title: Reading lamp schedule preview
      message: >-
        {% if plan_state == 'off' %}
          Would turn the reading lamp off.
        {% else %}
          Would set the reading lamp to {{ level }}% brightness.
        {% endif %}
mode: restart

The first trigger intentionally has no from or to. According to the state-trigger reference, that also detects attribute changes. Even a present but empty to: filters those out, so leave the key absent when checking this code after visual editing.

The two checks in the action list stop the run when paused or when data is unusable. Reading an attribute can return no value; the numeric check and range check prevent a missing setting from silently becoming zero brightness. A failed action-list condition stops subsequent steps.

The result appears in Home Assistant’s own notifications, not as a phone push alert. Reusing one notification ID replaces the previous preview. An old preview is a record of the last successful run; it is not a live health indicator.

4. Rehearse the boundary before connecting hardware

Use a temporary plan on today’s weekday: one block starting a few minutes from now, followed immediately by a second block, then a gap. Give each block at least two minutes so there is time to inspect the result. Keep the 70 and 25 values. Turn the schedule-enabled toggle on and watch the notification and the automation’s Traces, which show each run’s steps.

CheckExpected resultWhat it verifies
Enable during the first block“Would set the reading lamp to 70% brightness.”The current plan is applied without waiting for tomorrow.
First block touches the secondPreview changes to 25%; schedule remains on.Attribute changes reach the automation.
Second block ends“Would turn the reading lamp off.”The gap has an explicit action.
Pause before a boundaryNo new preview; the previous one remains.The pause check stops the action.
Resume during the second blockPreview changes to 25%.Resume reads the current setting.
Remove brightness data from an active test blockNo new preview; trace stops at the data check.Missing data is not interpreted as off. Restore the data afterward.

Do not change your server clock to accelerate the test. Restore the intended weekly blocks afterward. You can check startup behavior during a planned restart while this still only creates notifications; an enabled, valid schedule should produce the current preview when the system is ready.

The startup trigger starts a fresh evaluation. It does not replay missed blocks. If Home Assistant returns during the 25% block, the intended result is 25%, even if the 70% block happened while it was off. A later schedule-state update also gives this automation another opportunity to evaluate valid data.

5. Connect one dimmable lamp when the preview matches

First confirm that the existing lamp’s brightness slider works in Home Assistant. Record its actual light. entity ID. This walkthrough assumes that working connection; it does not establish compatibility with a particular bulb or bridge.

  1. Turn the schedule-enabled toggle off. Save a copy of the working preview YAML.
  2. Replace only the final persistent_notification.create action and its data with the block below. Keep the variables, both checks, triggers and mode.
  3. Replace both occurrences of light.reading_lamp with your lamp’s entity ID. Save, then enable the toggle while you are beside the lamp. A gap will turn it off; an active block will apply its brightness.
  - choose:
      - conditions: "{{ plan_state == 'off' }}"
        sequence:
          - action: light.turn_off
            target:
              entity_id: light.reading_lamp
    default:
      - action: light.turn_on
        target:
          entity_id: light.reading_lamp
        data:
          brightness_pct: "{{ level | int }}"

The replacement belongs inside actions:, at the same indentation as the removed notification action. A light that is already on can receive a new brightness through light.turn_on. The example does not add a fade or promise how quickly your device responds.

Keep one routine in charge. An existing adaptive-lighting or vendor schedule may overwrite this one. For a manual evening, pause this routine before adjusting the lamp. Resume applies the current plan immediately. See the manual override guide for broader household controls.

This version does not continually enforce brightness or retry failed lamp commands. If the lamp is unavailable at a scheduled change, restore its connection and cycle the schedule-enabled toggle off and on. After reloading automations, that also reapplies the current plan. Read the trace if the command still fails; repeated on/off requests are not a connection repair.

If the schedule and the room disagree

SymptomCheck firstNext step
First brightness works; second is missedDid a to or from filter get added? Is the data different in the second block?Restore the unrestricted schedule trigger and repeat the preview boundary test.
Nothing happens at any timeAutomation enabled, pause toggle on, correct IDs, and today’s blocksOpen the latest trace. If none exists, cycle the toggle to start a new run.
Trace stops at the data checkSchedule is on but brightness_pct is missing, nonnumeric, fractional or outside 1–100Correct the active block. An unknown or unavailable schedule also stops here.
Preview works but lamp does notLamp’s own brightness control and the command result in the traceResolve the light connection or capability issue before changing the timetable.
Setting changes unexpectedly laterAnother automation, vendor schedule or manual actionDecide which routine owns the lamp; preserve a clear manual pause.

Common questions

Does the helper turn devices on by itself?

No. It provides the timetable and active block’s data. An automation must translate those into device actions.

Can I make it follow sunset or skip holidays?

This example follows fixed weekday times. For changing daylight, use the sunset lighting guide. For public holidays and personal days off, use the Workday helper guide. Those are separate rules; the weekly plan alone does not know your exceptions.

Will this work without internet?

The helper and automation run on your Home Assistant server. The lamp’s control path determines whether the final command needs internet access; a local timetable does not turn a cloud-connected lamp into a locally controlled one.

For help planning routines with understandable household controls, see Tara’s home automation kit for local routines.