Angry DadAngry Dad
← All automations
Petsmedium

Who Let the Damned Dogs Out?

Both garage doors open = 3.8 seconds to a cross-road sprint. So the house screams until you close one.

I have a dog. I have a garage. I have kids. And there's a dog park literally over the road.

WCPGW?

Here's the maths. If one of the two garage doors is closed, el Doggo cannot escape. But if both are open — for maybe 3.8 seconds — Jacko is out of there at full tilt, across the road, into snoofer heaven.

The problem: at least one of the adults (I'll let you guess which one) and one of the kids have ADHD, and simply do not register an open door when we're marching from the garage to the backyard for some power-tool-fuelled dopamine.

Enter Home Assistant. I replaced the roller-door controller with an ESP32 and put a contact sensor on the internal garage door. Now HA knows the state of both doors.

The magic: when both doors are open together for more than a minute, HA sets three of the downstairs Google speakers to maximum volume and starts playing: "Both garage doors are open, secure the mad dog!"

Every… damned… minute. Until someone closes a door — or until we're out hunting for the leash we never put back on the launch pad, off to retrieve the wayward mutt from the dog park, scanning the road for suspicious stains the whole way.

This one's a perfect job for Node-RED: two sensors in, a 'both open?' check, a one-minute nag loop that resends every 60 seconds, and a reset the instant either door closes.

You'll need

  • ESP32 on the roller-door controller (ESPHome)
  • Contact sensor on the internal garage door
  • A Google/Nest speaker group ('Downstairs')
  • Node-RED with the Home Assistant nodes

The payoff

One closed door = no sprint to snoofer heaven, and no scanning the bitumen for stains on the way to the dog park.

The flow

Who Let the Damned Dogs Out? — Node-RED flow

The Node-RED flow

[
  {
    "id": "tab_dogs",
    "type": "tab",
    "label": "Who Let the Damned Dogs Out?",
    "disabled": false,
    "info": "Nags at full volume while both garage doors are open together."
  },
  {
    "id": "ha_server",
    "type": "server",
    "name": "Home Assistant",
    "addon": true
  },
  {
    "id": "ha_internal",
    "type": "server-state-changed",
    "z": "tab_dogs",
    "name": "Internal Door",
    "server": "ha_server",
    "version": 4,
    "entityId": "binary_sensor.garage_internal_door",
    "entityIdType": "exact",
    "outputInitially": true,
    "stateType": "str",
    "outputProperties": [
      {
        "property": "payload",
        "propertyType": "msg",
        "value": "",
        "valueType": "entityState"
      },
      {
        "property": "topic",
        "propertyType": "msg",
        "value": "internal",
        "valueType": "str"
      }
    ],
    "x": 140,
    "y": 100,
    "wires": [
      [
        "fn_both"
      ]
    ]
  },
  {
    "id": "ha_roller",
    "type": "server-state-changed",
    "z": "tab_dogs",
    "name": "Roller Door",
    "server": "ha_server",
    "version": 4,
    "entityId": "binary_sensor.garage_roller_door",
    "entityIdType": "exact",
    "outputInitially": true,
    "stateType": "str",
    "outputProperties": [
      {
        "property": "payload",
        "propertyType": "msg",
        "value": "",
        "valueType": "entityState"
      },
      {
        "property": "topic",
        "propertyType": "msg",
        "value": "roller",
        "valueType": "str"
      }
    ],
    "x": 140,
    "y": 160,
    "wires": [
      [
        "fn_both"
      ]
    ]
  },
  {
    "id": "fn_both",
    "type": "function",
    "z": "tab_dogs",
    "name": "Both open?",
    "func": "// Remember each door's latest state, then check if both are open.\nflow.set(msg.topic, msg.payload);\nconst internal = flow.get(\"internal\");\nconst roller = flow.get(\"roller\");\n\nif (internal === \"on\" && roller === \"on\") {\n    return [{ payload: \"start\" }, null];   // both open -> start the nag\n}\nreturn [null, { reset: true }];            // not both open -> stop the nag\n",
    "outputs": 2,
    "noerr": 0,
    "x": 360,
    "y": 130,
    "wires": [
      [
        "trg_nag"
      ],
      [
        "trg_nag"
      ]
    ]
  },
  {
    "id": "trg_nag",
    "type": "trigger",
    "z": "tab_dogs",
    "name": "Nag every 60s",
    "op1": "nag",
    "op1type": "str",
    "op2": "0",
    "op2type": "str",
    "duration": "-60",
    "extend": false,
    "overrideDelay": false,
    "units": "s",
    "reset": "",
    "bytopic": "all",
    "outputs": 1,
    "x": 580,
    "y": 130,
    "wires": [
      [
        "svc_volume"
      ]
    ]
  },
  {
    "id": "svc_volume",
    "type": "api-call-service",
    "z": "tab_dogs",
    "name": "Volume -> max",
    "server": "ha_server",
    "version": 5,
    "action": "media_player.volume_set",
    "entityId": [
      "media_player.downstairs"
    ],
    "data": "{\"volume_level\":1}",
    "dataType": "json",
    "x": 790,
    "y": 130,
    "wires": [
      [
        "svc_tts"
      ]
    ]
  },
  {
    "id": "svc_tts",
    "type": "api-call-service",
    "z": "tab_dogs",
    "name": "Announce",
    "server": "ha_server",
    "version": 5,
    "action": "tts.google_translate_say",
    "entityId": [
      "media_player.downstairs"
    ],
    "data": "{\"message\":\"Both garage doors are open, secure the mad dog!\"}",
    "dataType": "json",
    "x": 980,
    "y": 130,
    "wires": [
      []
    ]
  }
]

In Node-RED: ☰ menu → Import, paste this, then swap the entity IDs (binary_sensor.garage_*, media_player.downstairs) for your own.

Want the next one automatically?

One automation like this in your inbox every week.

Don't fancy the DIY?

Get Dycom Automation to do it properly.

Reading YAML isn't everyone's idea of a good night in. Dycom Automation — the grown-up, properly-insured version of all this — will design, install and tune your whole smart home for you. Same ruthless automations, none of the swearing.

Get it done by Dycom Automation