How to Add a New Service Switch
Relevant source files
The following files were used as context for generating this wiki page:This guide explains how to add a new service switch to the Overlord Network Kill Switch system. A "service switch" is a virtual switch in Apple HomeKit that allows users to block or unblock network access to a specific service (like a streaming platform) or for a specific purpose (like "SchoolWork"). The system achieves this by controlling Pi-hole domain lists or Ubiquiti firewall rules.
The overall architecture is designed to be easily extensible. Adding a new switch primarily involves configuration changes in three places: the backend server's config.ini, the Node-RED flow, and the Homebridge config.json. No code changes to the core application are typically required.
Sources: README.md, cgi-bin/controller.py
System Architecture
Before adding a switch, it's helpful to understand the data flow. A user action in HomeKit triggers a series of events that translate into a change on your network hardware.
This diagram shows the high-level architecture of the system.
Sources: README.md:100-119
Step 1: Define the Service in config.ini
The first step is to define what the new switch will control. This is done in the etc/config.ini file. The service can be a list of domains to block/allow on Pi-hole or a firewall rule/device group to manage on a Ubiquiti controller.
Sources: cgi-bin/controller.py:59-137
Pi-hole Domain-Based Service
To create a switch that controls access to a service by blocking its domains, add a new entry under the [block_domains] or [allow_domains] section.
- Key: A unique name for your service (e.g.,
hbomax,school_work). This name will be used in the API URL and MQTT topics. - Value: A list of domains (one per line) that should be blocked or allowed. These are treated as regex patterns.
Example config.ini for a Pi-hole service:
[block_domains]
hbomax =
hbo.com
hbomax.com
hbonow.com
school_work =
youtube.com
netflix.com
Sources: cgi-bin/controller.py:78-82
Ubiquiti Rule-Based Service
To create a switch that enables or disables a Ubiquiti firewall rule, add the rule name to the [ubiquiti_rules] section. The rule must already exist in your UniFi Network Controller.
Example config.ini for a Ubiquiti service:
[ubiquiti_rules]
# The value is a list of rule names, one per line
internet_access_rules =
Block-Kids-Internet
Guest-Network-Restrictions
The backend server reads these rule names and uses them to find the corresponding rule ID via the Ubiquiti API.
Sources: cgi-bin/controller.py:107-111, lib/ubiquity/ubiquity.py:150-166
Step 2: Understand the API Endpoints
Once a service is defined in config.ini, the backend FastAPI server automatically exposes endpoints to control it. The service name you defined becomes a path parameter in the API calls.
| Endpoint | Method | Description |
|---|---|---|
/pihole/enable/{domain_block} | POST | Enables a Pi-hole domain block group. |
/pihole/disable/{domain_block} | POST | Disables a Pi-hole domain block group. |
/pihole/status/{domain_block} | GET | Checks the status of a Pi-hole domain block group. |
/ubiquiti/enable_rule/{target} | GET | Enables a Ubiquiti firewall rule. |
/ubiquiti/disable_rule/{target} | GET | Disables a Ubiquiti firewall rule. |
/ubiquiti/status_rule/{target} | GET | Checks the status of a Ubiquiti firewall rule. |
Sources: AGENTS.md:32-49, lib/pihole/pihole_router.py:38-52, lib/ubiquity/ubiquity.py:485-507
Step 3: Configure Node-RED
Node-RED acts as the bridge between MQTT messages from Homebridge and the backend API. The provided dns.json flow is designed to handle this translation dynamically.
The flow listens on MQTT topics, parses the service name, and constructs the appropriate API request.
This diagram illustrates the logic within the "DNS" Node-RED flow for a Pi-hole service.
Sources: node_red_flows/dns.json
Key Node-RED Components
- MQTT In (
caa4cd33a29af8e6): Subscribes tocmnd/dns_controller/media/+/change. The+is a wildcard that captures the service name (e.g.,hbomax). - Common Parsing (
eef5d17a36f78509): Achangenode that uses JSONata to extract the service name from the topic and store it inmsg.target.$split(topic, "/")[3] - Function (
f2bf547fc050a016): A JavaScript function that builds the final API request. It checks the payload (true/false) to determine whether to call theenableordisableendpoint.// From node: f2bf547fc050a016 let webserver = flow.get('endpoint'); // ... msg.topic = `stat/dns_controller/media/${msg.target}/status` // ... if (msg.verb == "change") { msg.method = "POST" if (msg.payload == "true") msg.verb = "enable" if (msg.payload == "false") msg.verb = "disable" msg.url = `${webserver}/pihole/${msg.verb}/${msg.target}` } return msg; - HTTP Request (
9136b9ba2ceeaf98): Sends the request to the backend server. - MQTT Out (
5f2a033f8739bd4e): Publishes the new status received from the API back to an MQTT topic, which updates the switch state in HomeKit.
For a new service, you typically don't need to change the Node-RED flow as long as your service name and MQTT topics follow the existing pattern.
Sources: node_red_flows/dns.json
Step 4: Add the Switch to Homebridge
The final step is to create the user-facing switch in HomeKit by adding a new accessory to your Homebridge config.json file, using the homebridge-mqttthing plugin.
The configuration for the new switch must use MQTT topics that match the patterns expected by Node-RED. The service name from config.ini must be part of the topic path.
Homebridge config.json Example
Here is an example for a new service named hbomax, as defined in Step 1.
{
"type": "switch",
"name": "HBO",
"debounceRecvms": 100,
"topics": {
"getOnline": "stat/dns_controller/master/service_status",
"getOn": "stat/dns_controller/media/hbomax/status",
"setOn": "cmnd/dns_controller/media/hbomax/change"
},
"accessory": "mqttthing"
}
Sources: README.md:46-60
Topic Breakdown
| Topic | Purpose | Value |
|---|---|---|
getOn | Reads the current state of the switch. Node-RED publishes the API response to this topic. | true or false |
setOn | Publishes a command when the user toggles the switch. Node-RED listens to this topic. | true or false |
This sequence diagram shows the full interaction when a user toggles the "HBO" switch in HomeKit.
Summary
Adding a new service switch is a configuration-driven process that leverages the dynamic nature of the backend API and Node-RED flows. By defining a service in config.ini and creating a corresponding mqttthing accessory in Homebridge, you can quickly extend the system to control various aspects of your network without writing new application code. The key is to maintain consistent naming for your service across all configuration files and MQTT topics.