mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 01:26:11 -08:00
heuristics docs
This commit is contained in:
120
docs/DEVICE_HEURISTICS.md
Executable file
120
docs/DEVICE_HEURISTICS.md
Executable file
@@ -0,0 +1,120 @@
|
|||||||
|
# Icon and Type guessing: Device heuristics
|
||||||
|
|
||||||
|
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**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JSON Rule Format
|
||||||
|
|
||||||
|
Rules are defined in a file called `device_heuristics_rules.json` (located under `/back`), structured like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"dev_type": "Phone",
|
||||||
|
"icon_html": "<i class=\"fa-brands fa-apple\"></i>",
|
||||||
|
"matching_pattern": [
|
||||||
|
{ "mac_prefix": "001A79", "vendor": "Apple" }
|
||||||
|
],
|
||||||
|
"name_pattern": ["iphone", "pixel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Supported fields:
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| ------------------ | -------------------- | --------------------------------------------------------------- |
|
||||||
|
| `dev_type` | `string` | Type to assign if rule matches (e.g. `"Gateway"`, `"Phone"`) |
|
||||||
|
| `icon_html` | `string` | Icon (HTML string) to assign if rule matches. Encoded to base64 at load time. |
|
||||||
|
| `matching_pattern` | `array` | List of `{ mac_prefix, vendor }` objects for first strict and then loose matching |
|
||||||
|
| `name_pattern` | `array` *(optional)* | List of lowercase substrings (used with regex) |
|
||||||
|
| `ip_pattern` | `array` *(optional)* | Regex patterns to match IPs |
|
||||||
|
|
||||||
|
**Order in this array defines priority** — rules are checked top-down and short-circuit on first match.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Matching Flow (in Priority Order)
|
||||||
|
|
||||||
|
The function `guess_device_attributes(...)` runs a series of matching functions in strict order:
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. MAC + Vendor → match_mac_and_vendor()
|
||||||
|
2. Vendor only → match_vendor()
|
||||||
|
3. Name pattern → match_name()
|
||||||
|
4. IP pattern → match_ip()
|
||||||
|
5. Final fallback → defaults
|
||||||
|
```
|
||||||
|
|
||||||
|
### Even if defaults are passed in, matching continues
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Even if default_icon is passed, match_ip() and others will still run
|
||||||
|
if (not type_ or type_ == default_type) or (not icon or icon == 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**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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_mac_and_vendor(mac_clean, vendor, ...)`
|
||||||
|
|
||||||
|
* Looks for MAC prefix **and** vendor substring match
|
||||||
|
* Most precise
|
||||||
|
* Stops as soon as a match is found
|
||||||
|
|
||||||
|
### `match_vendor(vendor, ...)`
|
||||||
|
|
||||||
|
* Falls back to substring match on vendor only
|
||||||
|
* Ignores rules where `mac_prefix` is present (ensures this is really a fallback)
|
||||||
|
|
||||||
|
### `match_name(name, ...)`
|
||||||
|
|
||||||
|
* Lowercase name is compared against all `name_pattern` values using regex
|
||||||
|
* Good for user-assigned labels (e.g. "AP Office", "iPhone")
|
||||||
|
|
||||||
|
### `match_ip(ip, ...)`
|
||||||
|
|
||||||
|
* If IP is present and matches regex patterns under any rule, it returns that type/icon
|
||||||
|
* Usually used for gateways or local IP ranges
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Icons
|
||||||
|
|
||||||
|
* Each rule can define an `icon_html`, which is converted to a `icon_base64` on load
|
||||||
|
* 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
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Priority Mechanics
|
||||||
|
|
||||||
|
* JSON rules are evaluated **top-to-bottom**
|
||||||
|
* Matching is **first-hit wins** — no scoring, no weights
|
||||||
|
* Rules that are more specific (e.g. exact MAC prefixes) should be listed earlier
|
||||||
0
front/php/templates/language/fr_fr.json
Normal file → Executable file
0
front/php/templates/language/fr_fr.json
Normal file → Executable file
@@ -75,6 +75,7 @@ nav:
|
|||||||
- Database: DATABASE.md
|
- Database: DATABASE.md
|
||||||
- Settings: SETTINGS_SYSTEM.md
|
- Settings: SETTINGS_SYSTEM.md
|
||||||
- Versions: VERSIONS.md
|
- Versions: VERSIONS.md
|
||||||
|
- Icon and Type guessing: DEVICE_HEURISTICS.md
|
||||||
- Integrations:
|
- Integrations:
|
||||||
- Webhook Secret: WEBHOOK_SECRET.md
|
- Webhook Secret: WEBHOOK_SECRET.md
|
||||||
- API: API.md
|
- API: API.md
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ def match_name(
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
def match_ip_rule(
|
def match_ip(
|
||||||
ip: str,
|
ip: str,
|
||||||
default_type: str,
|
default_type: str,
|
||||||
default_icon: str
|
default_icon: str
|
||||||
@@ -215,7 +215,7 @@ def guess_device_attributes(
|
|||||||
|
|
||||||
# --- Loose IP-based fallback ---
|
# --- Loose IP-based fallback ---
|
||||||
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_rule(ip, default_type, default_icon)
|
type_, icon = match_ip(ip, default_type, default_icon)
|
||||||
|
|
||||||
# Final fallbacks
|
# Final fallbacks
|
||||||
type_ = type_ or default_type
|
type_ = type_ or default_type
|
||||||
|
|||||||
Reference in New Issue
Block a user