Mood Controller: Giving Your Home a Rhythm with Home Assistant

I have two young kids, a four-year-old and an eighteen-month-old. If you’re a parent, you know that a home with small children is just chaos. Bedtime happens when it happens. If it does. Movie night interrupts everything. Someone wakes up at 5 AM, someone else sleeps until 7. The house needs to keep track.

When I first set up Home Assistant, I did what I suppose everyone does : I created scenes. Morning scene, evening scene, movie scene. And for a while, it felt like there might something there but they kept piling as I was discovering the family pattern. After a time to try and sequence the pattern I realized something, they are just bookmarks. If my wife and I decide to start bingeing until late in the night. The last thing I want after closing the tv is to have living room lighted all over again. So I needed a way to figure out how the living room could know that the house is now in night mode and so the living room should set its way back in night mode instead of evening (when the movie started).

That’s the gap I kept running into. Home Assistant is incredibly powerful at connecting devices and triggering automations. But it lack in any sort of algorithm that could detect patterns of use and create a logic out of it. The thing needs to be a living thing that flows through moods, with rooms that sometimes need to diverge from the whole and then gracefully rejoin the group.

So I built Mood Controller : a modular system that gives Home Assistant what it was missing — a stateful rhythm that cascades from the house level down to individual rooms, while letting everyone its own autonomy when needed.

Think of it as the “Apple touch” for Home Assistant. It just works the way you’d expect it to.

GitHub : github.com/ZeFish/hass_mood_controller


The Problem : A Missing Rhythm

Yet incredibly powerful for connecting and automating devices. Home Assistant, lacks a built-in “rhythm” or stateful scene management system. The challenge arises when you want to temporarily override a room’s lighting and then have it revert to a global home-wide ambient state instead of the previous one.

There is also another fix on the way for free. Home assistant does not handle any manual override. This ensure you can actually override any room and it will never change again. It can even be protected from user request on house global mood swing.

The user experience is in fact just a standard ikea switch. Press the top button to brighten the lights and down to turn the lights off. In any of those case, another button press would goes back into the rhythm of the house.

Just that. Having a zigbee switch that actually works for me. I can turn on the lights, and the house will grow thru all its phase while I am not disturbed. When I’ll leave the room and after 5minutes of incoupencie, it find back its way to the rhythm of the house.


The Core : Moods and Presets

At its heart, Mood Controller embodies a state-centric hierarchical automation philosophy, where moods cascade from the house level down to individual rooms, yet each space retains the autonomy to maintain its own state when needed. The system uses minimal helpers that serve dual purposes as both configuration points and memory, ensuring your home can gracefully recover from any disruption.

The key insight is that family life operates on two levels simultaneously. The first level is the mood — the general ambiance of the home tied to the rhythm of the day. The second level is the preset — temporary overrides for specific needs within a room, without breaking the overall flow.

Scenes gave me the first level. What was missing was the second level : the ability to say “I need this room brighter right now, but when I’m done, bring it back to the mood of the house at the current time.”

Moods

These are high-level, home-wide scenes that define the general ambiance. They are the primary states of the home. You can create as many as you need. My personal implementation uses five principal moods tied to the time of day :

Presets

These are variations or modifications of a Mood, often used for manual control within a room without changing the underlying Mood. This allows for manual alternatives within the current mood without breaking the overall rhythm. My standard presets are :

This two-tiered system allows for both powerful, home-wide automation and intuitive, manual control via physical switches or dashboards.

Usage Examples

Here are some examples of how to call the mood_set script in your automations or dashboard actions.

# Change the mood of one or multiple areas
- service: script.mood_set
  data:
    target_areas:
      - living_room
      - kitchen
    mood: unwind
# Sync all rooms to the current home mood.
- service: script.mood_set
  data:
    mood: "{{ states('input_text.home_mood') }}"
    transition_time: 30
# Sync a specific room to the home mood.
# Useful for after an override,
# like when a movie finishes.
- service: script.mood_set
  data:
    target_areas:
      - living_room
    mood: "{{ states('input_text.home_mood') }}"
    transition_time: 5
# Refresh all rooms to their current state.
# This reverts any manual light changes
# that were made outside of the mood system.
- service: script.mood_set
# Refresh a single room.
- service: script.mood_set
  data:
    target_areas:
      - kitchen
# Set specific rooms to a new mood and preset.
- service: script.mood_set
  data:
    target_areas:
      - bedroom
      - children
    mood: night
    preset: default
# Toggle a preset for a physical switch.
# This call sets the kitchen to bright.
# If it's already bright, it toggles
# to the default preset.
- service: script.mood_set
  data:
    target_areas:
      - kitchen
    toggle: true
    preset: bright

How It Works : The Setup (4 Steps)

1. The Helpers : input_text.home_mood

The system relies on a few key components : Home Assistant helpers for state storage, a control script, and individual scripts for each mood.

State is stored using input_text helpers. This makes the current mood and preset of any area instantly accessible to other automations.

Helper Type Scope Description
input_text.home_mood input_text Global Stores the current active Mood for the entire home.
input_text.area_id_mood input_text Per Area (Optional) Stores the current Mood for a specific area (e.g., input_text.kitchen_mood).
input_text.area_id_preset input_text Per Area (Optional) Stores the current Preset for a specific area (e.g., input_text.kitchen_preset).
input_boolean.area_id_lock input_boolean Per Area (Optional) A lock to prevent an area from being changed by home-wide Mood calls.

Tip : You can still control areas that do not have dedicated input_text helpers. If you call mood_set with no target_areas, it will target all areas in your Home Assistant instance. For areas without helpers, it will apply the requested mood using the default preset. This is a great way to have secondary areas (like hallways or closets) follow the main home rhythm without needing their own complex state management.

2. The Controller : script.mood_set

This is the central nervous system of the entire setup. It is responsible for interpreting requests, determining which areas to change, and dispatching commands to the appropriate mood scripts.

- target_areas: The area(s) to apply the mood to. If left empty, applies to all unlocked areas.
- mood: the desired lighting mood (e.g., "morning", "off", "cozy").
- preset: optional override for brightness/configuration level (e.g., "bright", "dim").
- toggle: If true, toggles between the specified preset and 'default' when an area is already in the target preset state.
- transition_time: number of seconds for light transition (default: 2).

The “Smoking Gun” : Dynamic Script Execution

The core of this system’s flexibility comes from using Jinja2 templates to dynamically call scripts. A single action can trigger any mood script based on a variable, allowing for infinite scalability.

- variables:
    mood_script: "script.mood_{{ states('input_text.home_mood') }}"
- service: "{{ mood_script }}"
  data:
    target_areas: "{{ areas }}"
    preset: "{{ preset }}"
    transition_time: "{{ transition_time }}"
  alias: Call the mood script
  continue_on_error: true

This makes the system infinitely extensible. To add a new mood, you simply create a new script.mood_[newmood] and the system will handle it automatically.

3. The Automation : automation.home_mood_change

When the input_text.home_mood helper changes, it calls script.mood_set to propagate that change to all unlocked rooms. The beauty of it is that if you use any “Do not disturb” or “Away” mode, you can disable the automation so that it does not trigger. You can keep updating the input_text.house_mood to keep the moods flowing. When you turn on the automation, it will automatically propagate the mood to all unlocked rooms and keep your home just like you want it.

alias: Home mood change
description: It call script.mood_set when input_text.home_mood change
triggers:
  - entity_id:
      - input_text.home_mood
    to: null
    trigger: state
  - trigger: state
    entity_id:
      - automation.home_mood_change
    from: "off"
    to: "on"
conditions:
  - condition: state
    entity_id: script.mood_set
    state: "off"
    alias: This prevent possible infinite loop with mood_set
actions:
  - action: script.mood_set
    metadata: {}
    data:
      mood: "{{ states('input_text.home_mood') }}"
      transition_time: 30
mode: restart

4. The Mood : script.mood_{mood_name}

The Individual Mood Script Architecture

Each mood requires its own script (e.g., script.mood_morning). This script defines the specific scenes for each preset within that mood.

The script is structured into three main sections :

  1. Preset-Agnostic Actions : A parallel block where you can define actions that should run for a room whenever this mood is set, regardless of the preset. This is ideal for setting things like speaker volume.
  2. Preset Logic : A choose block that routes to the requested preset (defaultbrightoff, etc.) and applies the specific light settings for that preset in each targeted room.
  3. Home Wide Actions : A final section that runs only if the mood was applied to the entire home. This is useful for setting global variables, like a home-wide music playlist.

(See the GitHub repository for complete mood script templates.)


Practical Examples of Mood Rhythm

In my own home, I’ve created automations that define when moods change based on time, activity, and environmental data. This gives the house a rhythm that adapts fluidly throughout the day.

Here’s how my moods typically shift :

How the System Lives Throughout the House


Advanced Features

Area Locking

The system includes a locking mechanism to prevent mood changes in sensitive areas. If an input_boolean.[area_id]_lock is on, any mood_set call that targets a group of areas will automatically exclude the locked area.

Tip : A call made specifically to a single locked area will still go through. This is the desired behavior for in-room controls, allowing someone in a locked room to still adjust their own lights.

Performance Optimization

To ensure fast execution, script.mood_set intelligently groups areas by their required mood and preset combination. If 4 rooms need Morning/default and 1 room needs Morning/off, the script doesn’t make 5 individual calls. It makes two optimized calls. This significantly reduces overhead and execution time.

Event Hook : mood_setted

At the end of its execution, script.mood_set fires a custom event named mood_setted. This event includes all relevant parameters — such as the targeted areas, mood, preset, and whether the change is home-wide — allowing other automations to react dynamically.

- event: mood_setted
  event_data:
    target_areas: "{{ areas_resolved_unlocked }}"
    mood: "{{ mood_resovled }}"
    preset: "{{ preset_resolved }}"
    is_homewide: "{{ is_homewide }}"

Tip : I have a script that on birthdays or special occasions found in a calendar, it will call a script bound to that occasion and overwrite some lights after the moods have been set.


Real-World Automation Examples

The true power of this system is unlocked through automation. Because the state of every room is always known and stored in helpers, you can create highly specific and intelligent automations.

Motion-Based Night Light

Turns on a dim light in the kitchen upon motion, but only if the kitchen is in the Night mood and default preset. When motion clears, it gracefully returns the room to the standard Night scene.

(Full YAML available in the GitHub repository.)

Movie Time

Locks the living room when the projector turns on. When media plays, it sets the living room into movie mode. After a 30-second pause, the living room syncs back with the home mood. When the projector turns off, the living room gets unlocked and returns to whatever mood the house is in now — not whatever it was when the movie started.

This is the automation that convinced me the system was working. The house moved from Evening to Night during a two-hour movie, and when I turned off the projector, the living room gently faded into Night — not back to Evening. That’s rhythm.

Morning Routine

Each room transitions to Morning individually as motion is detected. When all main rooms have reached Morning, the whole home officially shifts. This means if one parent is up early with the baby, the kitchen wakes up softly without blasting light into the bedroom where the other parent is still sleeping.

Children’s Room Lock

Automatically locks the children’s room during Night and Unwind moods, preventing home-wide transitions from accidentally lighting up a room where a child is sleeping. When the mood changes to something else, the room unlocks and syncs back with the home.


What I Learned Building This

Mood Controller started as a way to solve a lighting problem, but it taught me something bigger about how systems should work. The best automation isn’t the one that does the most — it’s the one you forget is there. When the house just feels right without anyone touching a switch, that’s when you know the system is working.

The architecture behind this — state hierarchies, dynamic dispatch, event hooks, area autonomy — isn’t specific to Home Assistant. It’s a pattern that applies wherever you need to manage complex, overlapping states in a system that serves humans. I’ve used the same thinking to build modular web frameworks and I’m starting to apply it to physical computing projects like automated growing systems.

If you’re a Home Assistant user frustrated by the limitations of scenes and scripts, I hope this gives you a foundation to build on. The full code, templates, and documentation are on GitHub :

github.com/ZeFish/hass_mood_controller

If you have questions, ideas, or improvements — open an issue or reach out. I’d love to hear how you adapt this to your own home’s rhythm.


Francis Fontaine is a developer and photographer based in Québec City. He builds modular systems for the web (stnd.build) and for the physical world, and believes the best technology is the kind that disappears into the background of daily life.