mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
docs
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
# Icon and Type guessing: Device heuristics
|
# Device Heuristics: Icon and Type Guessing
|
||||||
|
|
||||||
This module is responsible for inferring the most likely **device type** and **icon** based on minimal identifying data like MAC address, vendor, IP, or device name.
|
This module is responsible for inferring the most likely **device type** and **icon** based on minimal identifying data like MAC address, vendor, IP, or device name.
|
||||||
|
|
||||||
It does this using a set of heuristics defined in an external JSON rules file, which it evaluates **in priority order**.
|
It does this using a set of heuristics defined in an external JSON rules file, which it evaluates **in priority order**.
|
||||||
|
|
||||||
|
>[!NOTE]
|
||||||
|
> You can find the full source code of the heuristics module in the `device_heuristics.py` file.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## JSON Rule Format
|
## JSON Rule Format
|
||||||
@@ -23,6 +26,9 @@ Rules are defined in a file called `device_heuristics_rules.json` (located under
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
>[!NOTE]
|
||||||
|
> Feel free to raise a PR in case you'd like to add any rules into the `device_heuristics_rules.json` file. Please place new rules into the correct position and consider the priority of already available rules.
|
||||||
|
|
||||||
### Supported fields:
|
### Supported fields:
|
||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
@@ -41,45 +47,30 @@ Rules are defined in a file called `device_heuristics_rules.json` (located under
|
|||||||
|
|
||||||
The function `guess_device_attributes(...)` runs a series of matching functions in strict order:
|
The function `guess_device_attributes(...)` runs a series of matching functions in strict order:
|
||||||
|
|
||||||
```text
|
1. MAC + Vendor → `match_mac_and_vendor()`
|
||||||
1. MAC + Vendor → match_mac_and_vendor()
|
2. Vendor only → `match_vendor()`
|
||||||
2. Vendor only → match_vendor()
|
3. Name pattern → `match_name()`
|
||||||
3. Name pattern → match_name()
|
4. IP pattern → `match_ip()`
|
||||||
4. IP pattern → match_ip()
|
5. Final fallback → defaults defined in the `NEWDEV_devIcon` and `NEWDEV_devType` settings.
|
||||||
5. Final fallback → defaults
|
|
||||||
```
|
|
||||||
|
|
||||||
### Even if defaults are passed in, matching continues
|
### Use of default values
|
||||||
|
|
||||||
For example, when `default_icon` is passed in from an external source (like `NEWDEV_devIcon`), that value **does not halt the guessing process**. The matchers still try to find a better match:
|
The guessing process runs for every device **as long as the current type or icon still matches the default values**. Even if earlier heuristics return a match, the system continues evaluating additional clues — like name or IP — to try and replace placeholders.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Even if default_icon is passed, match_ip() and others will still run
|
# Still considered a match attempt if current values are defaults
|
||||||
if (not type_ or type_ == default_type) or (not icon or icon == default_icon):
|
if (not type_ or type_ == default_type) or (not icon or icon == default_icon):
|
||||||
type_, icon = match_ip(ip, default_type, default_icon)
|
type_, icon = match_ip(ip, default_type, default_icon)
|
||||||
```
|
```
|
||||||
|
|
||||||
This is by design — you can pass in known fallbacks (e.g. `"unknown_icon"`), but the system will still guess and overwrite them **if it finds a better match**.
|
In other words: if the type or icon is still `"unknown"` (or matches the default), the system assumes the match isn’t final — and keeps looking. It stops only when both values are non-default (defaults are defined in the `NEWDEV_devIcon` and `NEWDEV_devType` settings).
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Defaults & Normalization
|
|
||||||
|
|
||||||
Input sanitization ensures missing data doesn’t break detection:
|
|
||||||
|
|
||||||
| Input | Normalized to |
|
|
||||||
| ------------- | --------------------- |
|
|
||||||
| `vendor=None` | `"unknown"` |
|
|
||||||
| `mac=None` | `"00:00:00:00:00:00"` |
|
|
||||||
| `ip=None` | `"169.254.0.0"` |
|
|
||||||
| `name=None` | `"(unknown)"` |
|
|
||||||
|
|
||||||
These placeholder values **still go through the matching pipeline**. This makes the logic robust and ensures IP- or name-based matching can still work even if MAC/Vendor are unknown.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Match Behavior (per function)
|
## Match Behavior (per function)
|
||||||
|
|
||||||
|
These functions are executed in the following order:
|
||||||
|
|
||||||
### `match_mac_and_vendor(mac_clean, vendor, ...)`
|
### `match_mac_and_vendor(mac_clean, vendor, ...)`
|
||||||
|
|
||||||
* Looks for MAC prefix **and** vendor substring match
|
* Looks for MAC prefix **and** vendor substring match
|
||||||
@@ -109,7 +100,7 @@ These placeholder values **still go through the matching pipeline**. This makes
|
|||||||
* If missing, it falls back to the passed-in `default_icon` (`NEWDEV_devIcon` setting)
|
* If missing, it falls back to the passed-in `default_icon` (`NEWDEV_devIcon` setting)
|
||||||
* If a match is found but icon is still blank, default is used
|
* If a match is found but icon is still blank, default is used
|
||||||
|
|
||||||
**TL;DR:** If a match sets the type but has no icon, the default icon is used. If the match has both, defaults are overridden.
|
**TL;DR:** Type and icon must both be matched. If only one is matched, the other falls back to the default.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,4 @@
|
|||||||
{
|
{
|
||||||
"__inputs": [
|
|
||||||
{
|
|
||||||
"name": "DS_PROMETHEUS",
|
|
||||||
"label": "Prometheus",
|
|
||||||
"description": "",
|
|
||||||
"type": "datasource",
|
|
||||||
"pluginId": "prometheus",
|
|
||||||
"pluginName": "Prometheus"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"__elements": {},
|
|
||||||
"__requires": [
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "barchart",
|
|
||||||
"name": "Bar chart",
|
|
||||||
"version": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "grafana",
|
|
||||||
"id": "grafana",
|
|
||||||
"name": "Grafana",
|
|
||||||
"version": "12.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "datasource",
|
|
||||||
"id": "prometheus",
|
|
||||||
"name": "Prometheus",
|
|
||||||
"version": "1.0.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "stat",
|
|
||||||
"name": "Stat",
|
|
||||||
"version": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "panel",
|
|
||||||
"id": "table",
|
|
||||||
"name": "Table",
|
|
||||||
"version": ""
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
@@ -61,14 +18,11 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"fiscalYearStartMonth": 0,
|
"fiscalYearStartMonth": 0,
|
||||||
"graphTooltip": 0,
|
"graphTooltip": 0,
|
||||||
"id": null,
|
"id": 7,
|
||||||
"links": [],
|
"links": [],
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": "Prometheus",
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
},
|
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"color": {
|
"color": {
|
||||||
@@ -77,8 +31,6 @@
|
|||||||
},
|
},
|
||||||
"decimals": 0,
|
"decimals": 0,
|
||||||
"mappings": [],
|
"mappings": [],
|
||||||
"max": 105,
|
|
||||||
"min": 0,
|
|
||||||
"thresholds": {
|
"thresholds": {
|
||||||
"mode": "absolute",
|
"mode": "absolute",
|
||||||
"steps": [
|
"steps": [
|
||||||
@@ -122,12 +74,8 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_total_devices",
|
"expr": "netalertx_connected_devices + netalertx_offline_devices",
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Total Devices",
|
"title": "Total Devices",
|
||||||
@@ -136,7 +84,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -190,12 +138,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_connected_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_connected_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Connected",
|
"title": "Connected",
|
||||||
@@ -204,7 +152,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -259,12 +207,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_favorite_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_favorite_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Favorites",
|
"title": "Favorites",
|
||||||
@@ -273,7 +221,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -328,12 +276,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_new_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_new_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New Devices",
|
"title": "New Devices",
|
||||||
@@ -342,7 +290,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -397,12 +345,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_down_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_down_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Down",
|
"title": "Down",
|
||||||
@@ -411,7 +359,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -466,12 +414,12 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
"expr": "netalertx_archived_devices",
|
|
||||||
"refId": "A",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_archived_devices",
|
||||||
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Archived",
|
"title": "Archived",
|
||||||
@@ -480,7 +428,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
"defaults": {
|
"defaults": {
|
||||||
@@ -605,31 +553,31 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"expr": "netalertx_connected_devices",
|
"expr": "netalertx_connected_devices",
|
||||||
"legendFormat": "Connected",
|
"legendFormat": "Connected",
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"expr": "netalertx_total_devices - (netalertx_connected_devices + netalertx_down_devices)",
|
"expr": "netalertx_total_devices - (netalertx_connected_devices + netalertx_down_devices)",
|
||||||
"legendFormat": "Offline",
|
"legendFormat": "Offline",
|
||||||
"refId": "B",
|
"refId": "B"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expr": "netalertx_down_devices",
|
|
||||||
"legendFormat": "Down Devices",
|
|
||||||
"refId": "C",
|
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
}
|
},
|
||||||
|
"expr": "netalertx_down_devices",
|
||||||
|
"legendFormat": "Down Devices",
|
||||||
|
"refId": "C"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Device Presence",
|
"title": "Device Presence",
|
||||||
@@ -638,7 +586,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"description": "Connected (Online) Devices",
|
"description": "Connected (Online) Devices",
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -826,15 +774,15 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "netalertx_device_status{device_status=\"Online\"}",
|
"expr": "netalertx_device_status{device_status=\"Online\"}",
|
||||||
"format": "table",
|
"format": "table",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Connected Devices",
|
"title": "Connected Devices",
|
||||||
@@ -892,7 +840,7 @@
|
|||||||
{
|
{
|
||||||
"datasource": {
|
"datasource": {
|
||||||
"type": "prometheus",
|
"type": "prometheus",
|
||||||
"uid": "${DS_PROMETHEUS}"
|
"uid": "PBFA97CFB590B2093"
|
||||||
},
|
},
|
||||||
"description": "Disconnected(Offline) Devices",
|
"description": "Disconnected(Offline) Devices",
|
||||||
"fieldConfig": {
|
"fieldConfig": {
|
||||||
@@ -1079,15 +1027,15 @@
|
|||||||
"pluginVersion": "12.0.0",
|
"pluginVersion": "12.0.0",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "PBFA97CFB590B2093"
|
||||||
|
},
|
||||||
"editorMode": "code",
|
"editorMode": "code",
|
||||||
"expr": "netalertx_device_status{device_status=\"Offline\"}",
|
"expr": "netalertx_device_status{device_status=\"Offline\"}",
|
||||||
"format": "table",
|
"format": "table",
|
||||||
"range": true,
|
"range": true,
|
||||||
"refId": "A",
|
"refId": "A"
|
||||||
"datasource": {
|
|
||||||
"type": "prometheus",
|
|
||||||
"uid": "${DS_PROMETHEUS}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "Disconnected Devices",
|
"title": "Disconnected Devices",
|
||||||
@@ -1143,6 +1091,7 @@
|
|||||||
"type": "table"
|
"type": "table"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"preload": false,
|
||||||
"refresh": "30s",
|
"refresh": "30s",
|
||||||
"schemaVersion": 41,
|
"schemaVersion": 41,
|
||||||
"tags": [],
|
"tags": [],
|
||||||
@@ -1156,7 +1105,6 @@
|
|||||||
"timepicker": {},
|
"timepicker": {},
|
||||||
"timezone": "browser",
|
"timezone": "browser",
|
||||||
"title": "NetAlertX Overview",
|
"title": "NetAlertX Overview",
|
||||||
"uid": "netalertx-overview_7_26_2025",
|
"uid": "netalertx-overview_8_4_2025",
|
||||||
"version": 7,
|
"version": 2
|
||||||
"weekStart": ""
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user