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.
| Time | Additional data | Intended result |
|---|---|---|
| 16:00–20:00 | brightness_pct: 70 | Reading light at 70% |
| 20:00–22:30 | brightness_pct: 25 | Lower evening light at 25% |
| Outside those blocks | No active block | Lamp 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
- Open Settings → Devices & services → Helpers → Create helper → Schedule. Name it Reading lamp plan.
- 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.
- Create a Toggle helper named Reading lamp schedule enabled. Leave it off during setup.
- Check the helpers’ entity IDs. The code expects
schedule.reading_lamp_planandinput_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.
| Check | Expected result | What 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 second | Preview 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 boundary | No new preview; the previous one remains. | The pause check stops the action. |
| Resume during the second block | Preview changes to 25%. | Resume reads the current setting. |
| Remove brightness data from an active test block | No 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.
- Turn the schedule-enabled toggle off. Save a copy of the working preview YAML.
- Replace only the final
persistent_notification.createaction and its data with the block below. Keep the variables, both checks, triggers andmode. - Replace both occurrences of
light.reading_lampwith 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
| Symptom | Check first | Next step |
|---|---|---|
| First brightness works; second is missed | Did 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 time | Automation enabled, pause toggle on, correct IDs, and today’s blocks | Open the latest trace. If none exists, cycle the toggle to start a new run. |
| Trace stops at the data check | Schedule is on but brightness_pct is missing, nonnumeric, fractional or outside 1–100 | Correct the active block. An unknown or unavailable schedule also stops here. |
| Preview works but lamp does not | Lamp’s own brightness control and the command result in the trace | Resolve the light connection or capability issue before changing the timetable. |
| Setting changes unexpectedly later | Another automation, vendor schedule or manual action | Decide 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.
