🦆

Navigation

🧑‍🦯

Defining Your Home

Part 3 - Write Automations in Nix

says ⮞ I use 20x magnification when I code and debug. I use emoji to simplify logs for myself. If you can't handle my code style you can disable most of it on this website by toggling the button in the navbar. Shall duck continue?

You can have a lot of fun here for sure.
Let the qwackin' begin!

Action Types Supported

All automations can execute actions.
There are four different types of actions that can be executed.
1. Shell Commands

⮞ View Shell Commands Action Type Example

{
  type = "shell";
  command = "echo 'Hello World'";
}

2. MQTT Messages

⮞ View MQTT Message Action Type Example

{
  type = "mqtt";
  topic = "zigbee2mqtt/device/set";
  message = ''{"state":"ON"}'';
}

3. Scene Activation

⮞ View Scene Action Type Example

{
  type = "scene"; 
  scene = "movie_time";
}

4. Simple String (legacy)

⮞ View Simple String Action Type Example

"echo 'Hello Ducks'"

Dark Time

It might be one of the most important automation. Short and boring - but important.
Define when motion sensors should trigger lights, and for how long they should be turned on.

⮞ View `config.house.darkTime` code block

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    darkTime = {
      enable = true;
      after = "14"; # 🦆 duck say ⮞ 2 PM
      before = "9"; # 🦆 duck say ⮞ 9 AM
      duration = "900"; # 🦆 duck say ⮞ defined in seconds, before turning off again
    };  
    
  };}

Greeting

When no motion has been detected in your house for x seconds - welcome you home with a greeting!

⮞ View `config.house.zigbee.automations.greeting` code block

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        greeting = {
          enable = true;
          awayDuration = "7200"; # 🦆 duck say ⮞ how many seconds away before trigger
          greeting = "Welcome back! Starting the party!"; # 🦆 duck say ⮞ greeting message that will be spoken over TTS
          delay = "10"; # 🦆 duck say ⮞ time in seconds before calling the greeting
          sayOnHost = "desktop"; # 🦆 duck say ⮞ on what host to play the TTS
          action = { 
            type = "shell"; # 🦆 duck say ⮞ or "mqtt" or "scene"
            command = ''
              # 🦆 duck say ⮞ imagination is the key
            '';
          };
        };   
      };
    };
    
  };}

⮞ simple huh? - i enjoy this auto a lot qwack



Automation Types

There are currently six different automation types:

Dimmer Action Automations

Configure your dimmers.
This is optional, as they have default action's pre-configured in zigduck-rs (next page).

Default actions are:
on_press_release: Turn on all zigbee devices with type 'light' in the dimmers room at last known state.
on_hold_release: Turn on all zigbee devices with type 'light' at maximum brightness.
up_press_release: Increase brightness of all zigbee devices with type 'light' in dimmers room.
up_hold_release: None.
down_press_release: Decrease brightness of all zigbee devices with type 'light' in dimmers room.
down_hold_release: None.
off_press_release: Turn off all zigbee devices with type 'light' in dimmer's room.
off_hold_release: Turn off all zigbee devices with type 'light'.

This is an example snippet of how a dimmer override automation may look:

⮞ View `config.house.zigbee.automations.dimmer_actions` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        dimmer_actions = {
          livingroom = { # 🦆 duck say ⮞ room
            off_hold_release = { # 🦆 duck say ⮞ or "on_press_release" or "on_hold_release" or "up_press_release" or "up_hold_release" or "down_press_release" or "down_hold_release" or "off_press_release" 
              enable = true;
              description = "Turn off all configured light devices";
              extra_actions = []; # 🦆 duck say ⮞ writing your actions here won't override default actions
              override_actions = [ # 🦆 duck say ⮞ writing them here will
                {
                  type = "mqtt";
                  topic = "zigbee2mqtt/Fläkt/set";
                  message = ''{"state":"OFF"}'';
                }
                {
                  type = "scene";
                  scene = "dark";
                }
              ];
            }; 
          };  
        };    
      };
    };
    
  };}

Global Action Automations

Supported Global Action Triggers:
"leak_detected" - When water sensors detect leaks.
"smoke_detected" - When smoke detectors trigger.

If you have smoke detectors or water sensors, this is a very important example:

⮞ View `config.house.zigbee.automations.global_actions` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        global_actions = { # 🦆 duck say ⮞ not room specific
          leak_detected = [ # 🦆 duck say ⮞ WATER?! WARNING! - then take bath yay
            {
              type = "shell";
              command = "${config.pkgs.yo}/bin/yo-notify '🚨 WATER LEAK DETECTED!'";
            }
            {
              type = "mqtt";
              topic = "zigbee2mqtt/all_valves/set";
              message = ''{"state":"OFF"}'';
            }
            "echo 'EMERGENCY: Water leak!' | wall"
          ];
  
          smoke_detected = [ 
            { # 🦆 duck say ⮞ dont like fire =(
              type = "shell"; 
              command = "${pkgs.paplay}/bin/paplay ${config.this.user.me.dotfilesDir}/modules/themes/sounds/fire-alarm.wav";
            }
            {
              type = "mqtt";
              topic = "zigbee2mqtt/all_lights/set";
              message = ''{"state":"ON", "brightness": 255, "color": {"hex": "FF0000"}}'';
            }
            "curl -X POST http://localhost:8080/emergency/fire"
          ];
        };
      };
    };
    
  };}

Room Action Automations

Supported Room Action Triggers:
"motion_detected" - When motion sensors detect movement.
Default Action: Turn on all light devices in the motion sensors room. (if darkTime)
"motion_not_detected" - When motion stops being detected.
Default Action: Turn off all light devices in the motion sensors room. (after time configured in darkTime)
"door_opened" - When door/window sensors open.
"door_closed" - When door/window sensors close.

Take a look at an example snippet of how a room action automation may look:

⮞ View `config.house.zigbee.automations.room_actions` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        room_actions = {
          hallway = { # 🦆 duck say ⮞ room
            # 🦆 says ⮞ zigbee device must be configured as type 'sensor'
            door_opened = [];
            door_closed = [];
          };  
          bedroom = { 
            # 🦆 says ⮞ default actions already configured - room lights will turn on upon motion (if darkTime)
            motion_detected = [
              {
                type = "scene";
                scene = "Chill Scene";
              }           
            ];
            motion_not_detected = [
              {
                type = "mqtt"; # 🦆 duck say ⮞ or "shell" or "scene"
                topic = "zigbee2mqtt/Sänggavel/set";
                message = ''{"state":"OFF", "brightness": 80}'';
              }              
            ];
          };
        };
      };
    };
  
  };}

MQTT Triggered Automations

Triggers the automation when a specified Mosquitto topic (and optionally message) is received and processed.
This enables the user to automate, well - basically anything.
Supported MQTT triggered Conditions:
"dark_time" - Checks: If current time is within configured dark time range.

⮞ View usage

{ type = "dark_time"; }
Here is an example snippet of how the mqtt triggered automation may look:

⮞ View `config.house.zigbee.automations.mqtt_triggered` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        mqtt_triggered = {
          dashboard_command = {
            enable = true;
            description = "Handle custom commands from web dashboard";
            topic = "house/command";
            message = null; # 🦆 says ⮞ match any message on this topic
            actions = [
              { # 🦆says⮞ these variables are passed to the shell script for usage 
                type = "shell";
                command = ''
                  echo "Topic: $MQTT_TOPIC"
                  echo "Device: $MQTT_DEVICE"
                  echo "Room: $MQTT_ROOM"
                  echo "Payload: $MQTT_PAYLOAD"
                  echo "Action: $MQTT_ACTION"
                  echo "State: $MQTT_STATE"
                '';
              }
            ];
          };
        };
      };
    };
    
  };}  

Time Based Action Automations

Triggers the automation on a specified time and days.
Supported Time Based Conditions:
"dark_time" - Checks: If current time is within configured dark time range.

⮞ View usage

{ type = "dark_time"; }
Here is an example snippet of how the time based automation may look:

⮞ View `config.house.zigbee.automations.time_based` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        time_based = {
          smart_wakeup = { # 🦆 duck say ⮞ pick a name
            enable = true;
            description = "Gradual wake-up with news and coffee";
            schedule = { # 🦆 duck say ⮞ when to run
              start = "06:30";
              end = "07:00";
              days = ["mon" "tue" "wed" "thu" "fri"]; # 🦆 duck say ⮞ and what days
            };
            conditions = [ # 🦆 duck say ⮞ only run when someone is home qwack
              { type = "someone_home"; value = true; }
            ]; 
            actions = [
              {
                type = "scene";
                scene = "sunrise_simulation";
              }
              {
                type = "shell";
                command = "${pkgs.mpg123}/bin/mpg123 ${config.this.user.me.dotfilesDir}/modules/themes/sounds/alarm.mp3";
              }
              {
                type = "mqtt";
                topic = "zigbee2mqtt/CoffeeMaker/set";
                message = ''{"state":"ON", "time": 300}'';
              }
              {
                type = "shell";
                command = "${config.pkgs.yo}/bin/yo-say 'Good morning! Time to wake up.'";
              }
            ];
          };
        };
      };
    };  
      
  };}

Presence Based Action Automations


Supported Presence Based Conditions:
"someone_home" - Checks: If someone is home.

⮞ View usage

{ 
  type = "someone_home"; 
  value = true;
}

"room_occupied" - Checks: If a specific room is occupied.
⮞ View usage

{
  type = "room_occupied";
  room = "livingroom";
  value = true;
}

Here is an example snippet of how the presence based automations may look:

⮞ View `config.house.zigbee.automations.presence_based` code example

{ # 🦆 duck say ⮞ my house - qwack 
  config,
  lib,
  pkgs,
  ...
} : let
in { # 🦆 duck say ⮞ autoqwack
  house = {
    zigbee = {
      automations = {
        presence_based = {
          arrival_party = { # 🦆 duck say ⮞ automation name
            enable = true;
            description = "Fun lighting when arriving home";
            motion_sensors = ["Front Door Motion"]; # 🦆 duck say ⮞ wat motion sensors 2 be affected
            no_motion_duration = 30; # 🦆 duck say ⮞ seconds
            conditions = [
              { type = "dark_time"; }
            ];
            actions = [ # 🦆 duck say ⮞ u knowz dis by now
              {
                type = "scene"; 
                scene = "welcome_home";
              }
              {
                type = "mqtt";
                topic = "zigbee2mqtt/DiscoBall/set";
                message = ''{"state":"ON", "speed": 200}'';
              }
            ];
          };
        };
      };  
    };
  
  };}

Important Notes:
Room names must match your house.rooms configuration.
Device names must match exactly what's in house.zigbee.devices
Global actions fire regardless of room context.
Room actions only fire for devices in that specific room.
All actions run sequentially when the trigger condition is met.

I hope you do see the full potential of this powerful automation system.
I realize it's a lot to take in at once, but hopefully I made it pretty clear of how it all works.
The examples are very basic, and that is how I recommend you start out if you are aiming to test this out.
Extending the configurations into complex automations is so simple it needs no instructions.

says ⮞ hope u had fun fwend!!

Keep Reading

Part 1. The module, the options and defining devices
Part 2. Configure your Mosquitto/Z2MQTT
Part 3. Nix Configured Automations ⮜🦆here u are
Part 4. Writing a Server Service - in Rust
Part 5. Writing a Client - With Voice Commands
Part 6. The Auto-Generated Dashboard


Comments on this blog post