mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-06 17:15:38 -08:00
wf work
This commit is contained in:
@@ -41,6 +41,10 @@ Send notifications to more than 80+ services, including Telegram via [Apprise](h
|
|||||||
Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. You can also
|
Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. You can also
|
||||||
build your own scanners with the [Plugin system](https://github.com/jokob-sk/NetAlertX/tree/main/docs/PLUGINS.md#readme) in as little as [15 minutes](https://www.youtube.com/watch?v=cdbxlwiWhv8).
|
build your own scanners with the [Plugin system](https://github.com/jokob-sk/NetAlertX/tree/main/docs/PLUGINS.md#readme) in as little as [15 minutes](https://www.youtube.com/watch?v=cdbxlwiWhv8).
|
||||||
|
|
||||||
|
### Workflows
|
||||||
|
|
||||||
|
The [workflows module](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WORKFLOWS.md) in NetAlertX allows to automate repetitive tasks, making network management more efficient. Whether you need to assign newly discovered devices to a specific Network Node, auto-group devices from a given vendor, unarchive a device if detected online, or automatically delete devices, this module provides the flexibility to tailor the automations to your needs.
|
||||||
|
|
||||||
|
|
||||||
## 📚 Documentation
|
## 📚 Documentation
|
||||||
<!--- --------------------------------------------------------------------- --->
|
<!--- --------------------------------------------------------------------- --->
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# `docker-compose.yaml` Examples
|
# `docker-compose.yaml` Examples
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> The container needs to run in `network_mode:"host"`.
|
> The container needs to run in `network_mode:"host"`. This also means that not all functionality is supported on a Widndows host as Docker for Windows doesn't support this networking option.
|
||||||
|
|
||||||
### Example 1
|
### Example 1
|
||||||
|
|
||||||
@@ -122,7 +122,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- TZ=Europe/London
|
- TZ=Europe/London
|
||||||
- PORT=20211
|
- PORT=20211
|
||||||
# network_mode: host
|
|
||||||
networks:
|
networks:
|
||||||
- outside
|
- outside
|
||||||
deploy:
|
deploy:
|
||||||
@@ -130,10 +129,6 @@ services:
|
|||||||
replicas: 1
|
replicas: 1
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
# placement: # ✅ Placement is now correctly inside deploy
|
|
||||||
# constraints:
|
|
||||||
# - node.role == manager
|
|
||||||
# - node.labels.device == NUC2
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
outside:
|
outside:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
NetAlertX comes with MQTT support, allowing you to show all detected devices as devices in Home Assistant. It also supplies a collection of stats, such as number of online devices.
|
NetAlertX comes with MQTT support, allowing you to show all detected devices as devices in Home Assistant. It also supplies a collection of stats, such as number of online devices.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> You can install NetAlertX also as a Home Assistant addon [](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) via the [alexbelgium/hassio-addons](https://github.com/alexbelgium/hassio-addons/). This is only possible if you run a supervised instance of Home Assistant. If not, you can still run NetAlertX in a separate Docker container and follow this guide to configure MQTT.
|
> You can install NetAlertX also as a Home Assistant addon [](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) via the [alexbelgium/hassio-addons](https://github.com/alexbelgium/hassio-addons/) repository. This is only possible if you run a supervised instance of Home Assistant. If not, you can still run NetAlertX in a separate Docker container and follow this guide to configure MQTT.
|
||||||
|
|
||||||
## ⚠ Note
|
## ⚠ Note
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Installation options
|
## Installation options
|
||||||
|
|
||||||
NetAlertX can be installed several ways. The best supported option is Docker, followed by a supervised the Home Assistant instance, as an Unraid app and lastly on bare metal.
|
NetAlertX can be installed several ways. The best supported option is Docker, followed by a supervised Home Assistant instance, as an Unraid app, and lastly, on bare metal.
|
||||||
|
|
||||||
- [[Installation] Docker (recommended)](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md)
|
- [[Installation] Docker (recommended)](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md)
|
||||||
- [[Installation] Home Assistant](https://github.com/alexbelgium/hassio-addons/tree/master/netalertx)
|
- [[Installation] Home Assistant](https://github.com/alexbelgium/hassio-addons/tree/master/netalertx)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ services:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
7. Replace the paths to your volume and/or comment out unnecessary line(s):
|
7. Replace the paths to your volume and comment out unnecessary line(s):
|
||||||
|
|
||||||
- This is only an example, your paths will differ.
|
- This is only an example, your paths will differ.
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Below are a few examples that demonstrate how this module can be used to simplif
|
|||||||
|
|
||||||
### Triggers
|
### Triggers
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Triggers define the event that activates a workflow. They monitor changes to objects within the system, such as updates to devices or the insertion of new entries. When the specified event occurs, the workflow is executed.
|
Triggers define the event that activates a workflow. They monitor changes to objects within the system, such as updates to devices or the insertion of new entries. When the specified event occurs, the workflow is executed.
|
||||||
|
|
||||||
#### Example Trigger:
|
#### Example Trigger:
|
||||||
@@ -32,7 +34,7 @@ Conditions determine whether a workflow should proceed based on certain criteria
|
|||||||
> [!TIP]
|
> [!TIP]
|
||||||
> To better understand how to use specific Device fields, please read through the [Database overview](./DATABASE.md) guide.
|
> To better understand how to use specific Device fields, please read through the [Database overview](./DATABASE.md) guide.
|
||||||
|
|
||||||
### Example Condition:
|
#### Example Condition:
|
||||||
- **Logic**: `AND`
|
- **Logic**: `AND`
|
||||||
- **Field**: `devVendor`
|
- **Field**: `devVendor`
|
||||||
- **Operator**: `contains` (case in-sensitive)
|
- **Operator**: `contains` (case in-sensitive)
|
||||||
@@ -48,7 +50,7 @@ Actions define the tasks that the workflow will perform once the conditions are
|
|||||||
|
|
||||||
You can include multiple actions that should execute once the conditions are met.
|
You can include multiple actions that should execute once the conditions are met.
|
||||||
|
|
||||||
### Example Action:
|
#### Example Action:
|
||||||
- **Action Type**: `update_field`
|
- **Action Type**: `update_field`
|
||||||
- **Field**: `devIsNew`
|
- **Field**: `devIsNew`
|
||||||
- **Value**: `0`
|
- **Value**: `0`
|
||||||
|
|||||||
34
docs/WORKFLOWS_DEBUGGING.md
Executable file
34
docs/WORKFLOWS_DEBUGGING.md
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
# Workflows debugging and troubleshooting
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Before troubleshooting, please ensure you have [Debugging enabled](./DEBUG_TIPS.md).
|
||||||
|
|
||||||
|
Workflows are triggered by various events. These events are captured and listed in the _Integrations -> App Events_ section of the application.
|
||||||
|
|
||||||
|
## Troubleshooting triggers
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Workflow events are processed once every 5 seconds. However, if a scan or other background tasks are running, this can cause a delay up to a few minutes.
|
||||||
|
|
||||||
|
If an event doesn't trigger a workflow as expected, check the _App Events_ section for the event. You can filter these by the ID of the device (`devMAC` or `devGUID`).
|
||||||
|
|
||||||
|
Once you find the _Event Guid_ and _Object GUID_, use them to find relevant debug entries.
|
||||||
|
|
||||||
|
Navigate to _Mainetenace -> Logs_ where you can filter the logs based on the _Event or Object GUID_.
|
||||||
|
|
||||||
|
Below you can find some example `app.log` entries that will help you understand why a Workflow was or was not triggered.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
16:27:03 [WF] Checking if '13f0ce26-1835-4c48-ae03-cdaf38f328fe' triggers the workflow 'Sample Device Update Workflow'
|
||||||
|
16:27:03 [WF] self.triggered 'False' for event '[[155], ['13f0ce26-1835-4c48-ae03-cdaf38f328fe'], [0], ['2025-04-02 05:26:56'], ['Devices'], ['050b6980-7af6-4409-950d-08e9786b7b33'], ['DEVICES'], ['00:11:32:ef:a5:6c'], ['192.168.1.82'], ['050b6980-7af6-4409-950d-08e9786b7b33'], [None], [0], [0], ['devPresentLastScan'], ['online'], ['update'], [None], [None], [None], [None]] and trigger {"object_type": "Devices", "event_type": "insert"}'
|
||||||
|
16:27:03 [WF] Checking if '13f0ce26-1835-4c48-ae03-cdaf38f328fe' triggers the workflow 'Location Change'
|
||||||
|
16:27:03 [WF] self.triggered 'True' for event '[[155], ['13f0ce26-1835-4c48-ae03-cdaf38f328fe'], [0], ['2025-04-02 05:26:56'], ['Devices'], ['050b6980-7af6-4409-950d-08e9786b7b33'], ['DEVICES'], ['00:11:32:ef:a5:6c'], ['192.168.1.82'], ['050b6980-7af6-4409-950d-08e9786b7b33'], [None], [0], [0], ['devPresentLastScan'], ['online'], ['update'], [None], [None], [None], [None]] and trigger {"object_type": "Devices", "event_type": "update"}'
|
||||||
|
16:27:03 [WF] Event with GUID '13f0ce26-1835-4c48-ae03-cdaf38f328fe' triggered the workflow 'Location Change'
|
||||||
|
```
|
||||||
|
|
||||||
|
Note how one trigger executed, but the other didn't based on different `"event_type"` values. One is `"event_type": "insert"`, the other `"event_type": "update"`.
|
||||||
|
|
||||||
|
Given the Event is a update event (note `...['online'], ['update'], [None]...` in the event structure), the `"event_type": "insert"` trigger didn't execute.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
docs/img/WORKFLOWS/trigger.jpg
Executable file
BIN
docs/img/WORKFLOWS/trigger.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -1857,6 +1857,11 @@ input[readonly] {
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.workflows
|
||||||
|
{
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
.workflows .col-sm-12, .workflows .col-sx-12
|
.workflows .col-sm-12, .workflows .col-sx-12
|
||||||
{
|
{
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
|||||||
0
front/php/templates/language/uk_ua.json
Normal file → Executable file
0
front/php/templates/language/uk_ua.json
Normal file → Executable file
@@ -66,6 +66,18 @@ let actionTypes = [
|
|||||||
"update_field", "delete_device"
|
"update_field", "delete_device"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let emptyWorkflow = {
|
||||||
|
"name": "New Workflow",
|
||||||
|
"trigger": {
|
||||||
|
"object_type": "Devices",
|
||||||
|
"event_type": "insert"
|
||||||
|
},
|
||||||
|
"conditions": [
|
||||||
|
],
|
||||||
|
"actions": [
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// Retrieve and process the data
|
// Retrieve and process the data
|
||||||
function getData() {
|
function getData() {
|
||||||
@@ -1073,17 +1085,7 @@ function updateWorkflowsJson(workflows)
|
|||||||
// Get empty workflow JSON
|
// Get empty workflow JSON
|
||||||
function getEmptyWorkflowJson()
|
function getEmptyWorkflowJson()
|
||||||
{
|
{
|
||||||
return {
|
return emptyWorkflow;
|
||||||
"name": "New Workflow",
|
|
||||||
"trigger": {
|
|
||||||
"object_type": "Devices",
|
|
||||||
"event_type": "create"
|
|
||||||
},
|
|
||||||
"conditions": [
|
|
||||||
],
|
|
||||||
"actions": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ nav:
|
|||||||
- Debugging Invalid JSON: DEBUG_INVALID_JSON.md
|
- Debugging Invalid JSON: DEBUG_INVALID_JSON.md
|
||||||
- Debugging Plugins: DEBUG_PLUGINS.md
|
- Debugging Plugins: DEBUG_PLUGINS.md
|
||||||
- Debugging Web UI Port: WEB_UI_PORT_DEBUG.md
|
- Debugging Web UI Port: WEB_UI_PORT_DEBUG.md
|
||||||
|
- Debugging Workflows: WORKFLOWS_DEBUGGING.md
|
||||||
- Development:
|
- Development:
|
||||||
- Plugin and app development:
|
- Plugin and app development:
|
||||||
- Environment Setup: DEV_ENV_SETUP.md
|
- Environment Setup: DEV_ENV_SETUP.md
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ class DB():
|
|||||||
|
|
||||||
return arr
|
return arr
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
def upgradeDB(self):
|
def upgradeDB(self):
|
||||||
"""
|
"""
|
||||||
@@ -929,4 +928,19 @@ def get_all_devices(db):
|
|||||||
return db.read(sql_devices_all)
|
return db.read(sql_devices_all)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def get_array_from_sql_rows(rows):
|
||||||
|
# Convert result into list of lists
|
||||||
|
arr = []
|
||||||
|
for row in rows:
|
||||||
|
if isinstance(row, sqlite3.Row):
|
||||||
|
arr.append(list(row)) # Convert row to list
|
||||||
|
elif isinstance(row, (tuple, list)):
|
||||||
|
arr.append(list(row)) # Already iterable, just convert to list
|
||||||
|
else:
|
||||||
|
arr.append([row]) # Handle single values safely
|
||||||
|
|
||||||
|
return arr
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ class ConditionGroup:
|
|||||||
|
|
||||||
def __init__(self, group_json):
|
def __init__(self, group_json):
|
||||||
|
|
||||||
mylog('none', ["[WF] json.dumps(group_json)"])
|
mylog('verbose', [f"[WF] ConditionGroup json.dumps(group_json): {json.dumps(group_json)}"])
|
||||||
mylog('none', [json.dumps(group_json)])
|
|
||||||
mylog('none', [group_json])
|
|
||||||
|
|
||||||
self.logic = group_json.get("logic", "AND").upper()
|
self.logic = group_json.get("logic", "AND").upper()
|
||||||
self.conditions = []
|
self.conditions = []
|
||||||
@@ -78,6 +76,6 @@ class ConditionGroup:
|
|||||||
elif self.logic == "OR":
|
elif self.logic == "OR":
|
||||||
return any(results)
|
return any(results)
|
||||||
else:
|
else:
|
||||||
m = f"[WF] Unsupported logic: {self.logic}"
|
m = f"[WF] ConditionGroup unsupported logic: {self.logic}"
|
||||||
mylog('none', [m])
|
mylog('verbose', [m])
|
||||||
raise ValueError(m)
|
raise ValueError(m)
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ class WorkflowManager:
|
|||||||
|
|
||||||
# Ensure workflow is enabled before proceeding
|
# Ensure workflow is enabled before proceeding
|
||||||
if workflow.get("enabled", "No").lower() == "yes":
|
if workflow.get("enabled", "No").lower() == "yes":
|
||||||
|
|
||||||
|
mylog('debug', [f"[WF] Checking if '{event["GUID"]}' triggers the workflow '{workflow["name"]}'"])
|
||||||
|
|
||||||
# construct trigger object which also evaluates if the current event triggers it
|
# construct trigger object which also evaluates if the current event triggers it
|
||||||
trigger = Trigger(workflow["trigger"], event, self.db)
|
trigger = Trigger(workflow["trigger"], event, self.db)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
# Register NetAlertX directories
|
# Register NetAlertX directories
|
||||||
INSTALL_PATH="/app"
|
INSTALL_PATH="/app"
|
||||||
@@ -7,6 +8,7 @@ sys.path.extend([f"{INSTALL_PATH}/server"])
|
|||||||
import conf
|
import conf
|
||||||
from logger import mylog, Logger
|
from logger import mylog, Logger
|
||||||
from helper import get_setting_value, timeNowTZ
|
from helper import get_setting_value, timeNowTZ
|
||||||
|
from database import get_array_from_sql_rows
|
||||||
|
|
||||||
# Make sure log level is initialized correctly
|
# Make sure log level is initialized correctly
|
||||||
Logger(get_setting_value('LOG_LEVEL'))
|
Logger(get_setting_value('LOG_LEVEL'))
|
||||||
@@ -27,7 +29,8 @@ class Trigger:
|
|||||||
self.event = event # Store the triggered event context, if provided
|
self.event = event # Store the triggered event context, if provided
|
||||||
self.triggered = self.object_type == event["ObjectType"] and self.event_type == event["AppEventType"]
|
self.triggered = self.object_type == event["ObjectType"] and self.event_type == event["AppEventType"]
|
||||||
|
|
||||||
mylog('verbose', [f"[WF] self.triggered '{self.triggered}'"])
|
mylog('debug', [f"""[WF] self.triggered '{self.triggered}' for event '{get_array_from_sql_rows(event)} and trigger {json.dumps(triggerJson)}' """])
|
||||||
|
|
||||||
|
|
||||||
if self.triggered:
|
if self.triggered:
|
||||||
# object type corresponds with the DB table name
|
# object type corresponds with the DB table name
|
||||||
|
|||||||
Reference in New Issue
Block a user