1/ Fix {} arround user_notifications.json file => if there is just one file, this create a file named "{user_notifications.json} ;)
2/ Fix group for the above file
This wasn't working for EMQX due to callback trigger delays it never connected. Also added a reconnect feature and a client id so it looks better in the EMQX connection dashboard. No confirmed to be working with Mosquitto and EMQX
Removed DEFER from ui_components as the device details page would not populate any more and the browser console would throw errors re function not found
Chnaged client creation logic to V2 API as we are already using Paho2.0. Chnaged version selection from Paho version (which should not have been a user choice) to MQTT Protocol selection, which can be v3 or v5. Most modern MQQTT brokers like Mosquitta or EMQX support v5.
description:Please search to see if an open or closed issue already exists for the feature you are requesting.
options:
- label:I have searched the existing open and closed issues
required:true
- type:textarea
attributes:
label:Is your feature request related to a problem? Please describe
description:A clear and concise description of what the problem is.
validations:
required:true
- type:textarea
attributes:
label:Describe the solution you'd like
description:A clear and concise description of what you want to happen.
validations:
required:true
- type:textarea
attributes:
label:Describe alternatives you've considered
description:A clear and concise description of any alternative solutions or features you've considered.
validations:
required:true
- type:textarea
attributes:
label:Anything else?
description:|
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required:true
- type:checkboxes
attributes:
label:Am I willing to test this? 🧪
description:I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
options:
- label:I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
required:true
- type:checkboxes
attributes:
label:Can I help implement this? 👩💻👨💻
description:The maintainer will provide guidance and help. The implementer will read the PR guidelines https://jokob-sk.github.io/NetAlertX/DEV_ENV_SETUP/
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
## Describe the issue
> When submitting an issue ❗[enable debug](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)❗ and [have a look at the docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs)
[describe your issue]
## Paste your `pialert.conf` (remove personal info)
```
paste_here
```
## Paste your `docker-compose.yml` and `.env` (remove personal info)
`docker-compose.yml`
```
paste_here
```
`.env`
```
paste_here
```
## Screenshots
[If applicable, add screenshots to help explain your problem.]
## Paste last few lines from `pialert.log`
> You can use `tail -100 /home/pi/pialert/front/log/pialert.log`
description:'When submitting an issue enable LOG_LEVEL="trace" and have a look at the docs.'
labels:['bug 🐛']
body:
- type:checkboxes
attributes:
label:Is there an existing issue for this?
description:Please search to see if an open or closed issue already exists for the bug you encountered.
options:
- label:I have searched the existing open and closed issues and I checked the docs https://jokob-sk.github.io/NetAlertX/
required:true
- type:checkboxes
attributes:
label:The issue occurs in the following browsers. Select at least 2.
description:This step helps me understand if this is a cache or browser-specific issue.
options:
- label:"Firefox"
- label:"Chrome"
- label:"Edge"
- label:"Safari (unsupported) - PRs welcome"
- label:"N/A - This is an issue with the backend"
- type:textarea
attributes:
label:Current Behavior
description:A concise description of what you're experiencing.
validations:
required:true
- type:textarea
attributes:
label:Expected Behavior
description:A concise description of what you expected to happen.
validations:
required:true
- type:textarea
attributes:
label:Steps To Reproduce
description:Steps to reproduce the behavior.
placeholder:|
1. With these settings...
2. With this config...
3. Run '...'
4. See error...
validations:
required:false
- type:textarea
attributes:
label:app.conf
description:|
Paste your `app.conf` (remove personal info)
render:python
validations:
required:false
- type:textarea
attributes:
label:docker-compose.yml
description:|
Paste your `docker-compose.yml`
render:python
validations:
required:false
- type:dropdown
id:installation_type
attributes:
label:What installation are you running?
options:
- Production (netalertx)
- Dev (netalertx-dev)
- Home Assistant (addon)
- Home Assistant fa (full-access addon)
- Bare-metal (community only support - Check Discord)
validations:
required:true
- type:textarea
attributes:
label:app.log
description:|
Logs with debug enabled (https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md) ⚠
***Generally speaking, all bug reports should have logs provided.***
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
You can use `tail -100 /app/log/app.log` in the container if you have trouble getting to the log files.
validations:
required:false
- type:checkboxes
attributes:
label:Debug enabled
description:I confirm I enabled `debug`
options:
- label:I have read and followed the steps in the wiki link above and provided the required debug logs and the log section covers the time when the issue occurs.
description:'When submitting an issue enable LOG_LEVEL="trace" and re-search first.'
labels:['Setup 📥']
body:
- type:checkboxes
attributes:
label:Did I research?
description:Please confirm you checked the usual places before opening a setup support request.
options:
- label:I have searched the docs https://jokob-sk.github.io/NetAlertX/
required:true
- label:I have searched the existing open and closed issues
required:true
- label:I confirm my SCAN_SUBNETS is configured and tested as per https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md
required:true
- type:checkboxes
attributes:
label:The issue occurs in the following browsers. Select at least 2.
description:This step helps me understand if this is a cache or browser-specific issue.
options:
- label:"Firefox"
- label:"Chrome"
- label:"Other (unsupported) - PRs welcome"
- label:"N/A - This is an issue with the backend"
- type:textarea
attributes:
label:What I want to do
description:Describe what you want to achieve.
validations:
required:false
- type:textarea
attributes:
label:Relevant settings you changed
description:|
Paste a screenshot or setting values of the settings you changed.
validations:
required:false
- type:textarea
attributes:
label:docker-compose.yml
description:|
Paste your `docker-compose.yml`
render:python
validations:
required:false
- type:dropdown
id:installation_type
attributes:
label:What installation are you running?
options:
- Production (netalertx)
- Dev (netalertx-dev)
- Home Assistant (addon)
- Home Assistant fa (full-access addon)
- Bare-metal (community only support - Check Discord)
validations:
required:true
- type:textarea
attributes:
label:app.log
description:|
Logs with debug enabled (https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md) ⚠
***Generally speaking, all bug reports should have logs provided.***
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
You can use `tail -100 /app/log/app.log` in the container if you have trouble getting to the log files.
validations:
required:false
- type:checkboxes
attributes:
label:Debug enabled
description:I confirm I enabled `debug`
options:
- label:I have read and followed the steps in the wiki link above and provided the required debug logs and the log section covers the time when the issue occurs.
Get visibility of what's going on on your WIFI/LAN network. Scan for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system.
# NetAlertX - Network, presence scanner and alert framework
Most of us don't know what's going on on our home network, but we want our family and data to be safe. _Command-line tools_ are great, but the output can be _hard to understand_ and action if you are not a network specialist.
PiAlert gives you peace of mind. _Visualize and immediately report 📬_ what is going on in your network - this is the first step to enhance your _network security 🔐_.
_PiAlert combines several network and other scanning tools 🔍 with notifications 📧 into one user-friendly package 📦_. You get an overview of network device Sessions, Connected devices, Events, Presence, Down alerts, and IPs. You can schedule Nmap scans to detect changes in device ports and visualize your Network topology (even with undetectable, dummy devices).
Setup a _kill switch ☠_ for your network via a smart plug with the available [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md) integration. Implement custom automations with the [CSV device Exports 📤](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/csv_backup), [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md), or [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) features.
Extend the app if you want to create your own scanner [Plugin](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) and handle the results and notifications in PiAlert.
Looking forward to your contributions if you decide to share your work with the community ❤.
## Scan Methods, Notifications, Integration, Extension system
| Features | Details |
|-------------|-------------|
| 🔍 | The app scans your network for, **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Discovery & scan methods include: **arp-scan**. **Pi-hole - DB import**, **Pi-hole - DHCP leases import**, **Generic DHCP leases import**. **UNIFI controller import**, **SNMP-enabled router import**. Check the [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) docs for more info on individual scans. |
|📧 | Send notifications to more than 80+ services, including Telegram via [Apprise](https://hub.docker.com/r/caronc/apprise), or use [Pushsafer](https://www.pushsafer.com/), or [NTFY](https://ntfy.sh/). |
|🧩 | Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. |
|➕ | Build your own scanners with the [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) |
Get visibility of what's going on on your WIFI/LAN network and enable presence detection of important devices. Schedule scans for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugin](https://github.com/jokob-sk/NetAlertX/tree/main/docs/PLUGINS.md#readme) with auto-generated UI and in-build notification system. Build out and easily maintain your network source of truth (NSoT).
Head to [https://netalertx.com/](https://netalertx.com/) for even more gifs and screenshots 📷.
</details>
## 📦 Features
### Scanners
The app scans your network for **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Discovery & scan methods include: **arp-scan**, **Pi-hole - DB import**, **Pi-hole - DHCP leases import**, **Generic DHCP leases import**, **UNIFI controller import**, **SNMP-enabled router import**. Check the [Plugins](https://github.com/jokob-sk/NetAlertX/tree/main/docs/PLUGINS.md#readme) docs for a full lits of avaliable plugins.
### Notification gateways
Send notifications to more than 80+ services, including Telegram via [Apprise](https://hub.docker.com/r/caronc/apprise), or use native [Pushsafer](https://www.pushsafer.com/), [Pushover](https://www.pushover.net/), or [NTFY](https://ntfy.sh/) publishers.
### Integrations and Plugins
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).
### Workflows
The [workflows module](https://github.com/jokob-sk/NetAlertX/blob/main/docs/WORKFLOWS.md) 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.
- Regular updates to keep your data and family safe 🔄
- Better and more functionality➕
- I don't get burned out and the app survives longer🔥🤯
- Quicker and better support with issues 🆘
- Less grumpy me 😄
| [](https://github.com/sponsors/jokob-sk) | [](https://www.buymeacoffee.com/jokobsk) | [](https://www.patreon.com/user?u=84385063) |
Thank you to everyone who appreciates this tool and donates.
<details>
<summary>Click for more ways to donate</summary>
<hr>
| [](https://github.com/sponsors/jokob-sk) | [](https://www.buymeacoffee.com/jokobsk) | [](https://www.patreon.com/user?u=84385063) |
This project would be nothing without the amazing work of the community, with special thanks to:
> [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert) (the original creator of PiAlert), [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and much more), [Macleykun](https://github.com/Macleykun) (Help with Dockerfile clean-up), [vladaurosh](https://github.com/vladaurosh) for Alpine re-base help, [Final-Hawk](https://github.com/Final-Hawk) (Help with NTFY, styling and other fixes), [TeroRERO](https://github.com/terorero) (Spanish translations), [Data-Monkey](https://github.com/Data-Monkey), (Split-up of the python.py file and more), [cvc90](https://github.com/cvc90) (Spanish translation and various UI work) to name a few. Check out all the [amazing contributors](https://github.com/jokob-sk/NetAlertX/graphs/contributors).
### 🌍 Translations
Proudly using [Weblate](https://hosted.weblate.org/projects/pialert/). Help out and suggest languages in the [online portal of Weblate](https://hosted.weblate.org/projects/pialert/core/).
> GPL 3.0 | [Read more here](LICENSE.txt) | Source of the [animated GIF (Loading Animation)](https://commons.wikimedia.org/wiki/File:Loading_Animation.gif) | Source of the [selfhosted Fonts](https://github.com/adobe-fonts/source-sans)
### Special thanks
This code is a collaborative body of work, with special thanks to:
> [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert) (the original creator of PiAlert), [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and much more), [Macleykun](https://github.com/Macleykun) (Help with Dockerfile clean-up) [Final-Hawk](https://github.com/Final-Hawk) (Help with NTFY, styling and other fixes), [TeroRERO](https://github.com/terorero) (Spanish translations), [Data-Monkey](https://github.com/Data-Monkey), (Split-up of the python.py file and more), [cvc90](https://github.com/cvc90) (Spanish translation and various UI work) to name a few...
>
> Please see the [Git contributors](https://github.com/jokob-sk/Pi.Alert/graphs/contributors) for a full list of people and their contributions to the project
Head to [https://netalertx.com/](https://netalertx.com/) for more gifs and screenshots 📷.
> [!NOTE]
> There is also an experimental 🧪 [bare-metal install](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md) method available.
## 📕 Basic Usage
- You will have to run the container on the host network, e.g:
> [!WARNING]
> You will have to run the container on the `host` network and specify `SCAN_SUBNETS` unless you use other [plugin scanners](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md). The initial scan can take a few minutes, so please wait 5-10 minutes for the initial discovery to finish.
| `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` |
|`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|`HOST_USER_GID` |User ID (UID) to map the user in the container to a server user with sufficient read&write permissions on the mapped files | `1000` |
|`HOST_USER_ID` |User Group ID (GID) to map the user group in the container to a server user group with sufficient read&write permissions on the mapped files | `1000` |
|`LOADED_PLUGINS` | Default [plugins](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md) to load. Plugins cannot be loaded with `APP_CONF_OVERRIDE`, you need to use this variable instead and then specify the plugins settings with `APP_CONF_OVERRIDE`. | `["PIHOLE","ASUSWRT"]` |
|`ALWAYS_FRESH_INSTALL` | ⚠ If `true` will delete the content of the `/db`&`/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`netalertx-dev` image. | `true` |
> You can override the default GraphQL port setting `GRAPHQL_PORT` (set to `20212`) by using the `APP_CONF_OVERRIDE` env variable. `LOADED_PLUGINS` and settings in `APP_CONF_OVERRIDE` can be specified via the UI as well.
| **Required** | `:/home/pi/pialert/config` | Folder which will contain the `pialert.conf` file (see below for details) |
| **Required** | `:/home/pi/pialert/db` | Folder which will contain the `pialert.db` file |
|Optional| `:/home/pi/pialert/front/log` | Logs folder useful for debugging if you have issues setting up the container |
|Optional| `:/etc/pihole/pihole-FTL.db` | PiHole's `pihole-FTL.db` database file. Required if you want to use PiHole |
|Optional| `:/etc/pihole/dhcp.leases` | PiHole's `dhcp.leases` file. Required if you want to use PiHole `dhcp.leases` file. This has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry. (the path in the container must contain `pihole`)|
|Optional| `:/home/pi/pialert/front/api` | A simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
|Optional| `:/home/pi/pialert/front/plugins/<plugin>/ignore_plugin` | Map a file `ignore_plugin` to ignore a plugin. Plugins can be soft-disabled via settings. More in the [Plugin docs](/front/plugins/README.md). |
> [!NOTE]
> See also [Backup strategies](https://github.com/jokob-sk/NetAlertX/blob/main/docs/BACKUPS.md).
| ✅ | `:/app/config` | Folder which will contain the `app.conf`&`devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
| ✅ | `:/app/db` | Folder which will contain the `app.db` database file |
| | `:/app/log` | Logs folder useful for debugging if you have issues setting up the container |
| | `:/app/api` | A simple [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
| | `:/app/front/plugins/<plugin>/ignore_plugin` | Map a file `ignore_plugin` to ignore a plugin. Plugins can be soft-disabled via settings. More in the [Plugin docs](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md). |
| | `:/etc/resolv.conf` | Use a custom `resolv.conf` file for [better name resolution](https://github.com/jokob-sk/NetAlertX/blob/main/docs/REVERSE_DNS.md). |
### Config (`pialert.conf`)
> Use separate `db` and `config` directories, do not nest them.
- If unavailable, the app generates a default `pialert.conf` and `pialert.db` file on the first run.
- The preferred way is to manage the configuration via the Settings section in the UI.
- You can modify [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directly, if needed.
### Initial setup
#### Important settings
- If unavailable, the app generates a default `app.conf` and `app.db` file on the first run.
- The preferred way is to manage the configuration via the Settings section in the UI, if UI is inaccessible you can modify [app.conf](https://github.com/jokob-sk/NetAlertX/tree/main/back) in the `/app/config/` folder directly
These are the most important settings to get at least some output in your Devices screen. Usually, only one approach is used, but you should be able to combine these approaches.
#### Setting up scanners
##### For arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
You have to specify which network(s) should be scanned. This is done by entering subnets that are accessible from the host. If you use the default `ARPSCAN` plugin, you have to specify at least one valid subnet and interface in the `SCAN_SUBNETS` setting. See the documentation on [How to set up multiple SUBNETS, VLANs and what are limitations](https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md) for troubleshooting and more advanced scenarios.
- ❗ To use the arp-scan method, you need to set the `SCAN_SUBNETS` variable. See the documentation on how [to setup SUBNETS, VLANs & limitations](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
##### For pihole: PIHOLE_RUN, DHCPLSS_RUN
There are 2 approaches how to get PiHole devices imported. Via the PiHole import (PIHOLE) plugin or DHCP leases (DHCPLSS) plugin.
**PiHole(Device sync)**
* `PIHOLE_RUN`:You need to map `:/etc/pihole/pihole-FTL.db` in the `docker-compose.yml` file if you enable this setting.
**DHCPLeases (Device import)**
* `DHCPLSS_RUN`:You need to map `:/etc/pihole/dhcp.leases` in the `docker-compose.yml` file if you enable this setting.
*The above setting has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole` as PiHole uses a different format of the `dhcp.leases` file).
If you are running PiHole you can synchronize devices directly. Check the [PiHole configuration guide](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PIHOLE_GUIDE.md) for details.
> [!NOTE]
> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
> You can bulk-import devices via the [CSV import method](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md).
#### Community guides
#### 🧭 Community guides
You can read or watch several [community configuration guides](https://github.com/jokob-sk/NetAlertX/blob/main/docs/COMMUNITY_GUIDES.md) in Chinese, Korean, German, or French.
> Primarily use the official installation guides in this document and use community content as suplementary material. Open an issue if you'd like to add your link to the list 🙏
- 📄 [How to Install Pi.Alert on Your Synology NAS - Marius hosting (English)](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
- 📄 [시놀/헤놀에서 네트워크 스캐너 Pi.Alert Docker로 설치 및 사용하기 (Korean)](https://blog.dalso.org/article/%EC%8B%9C%EB%86%80-%ED%97%A4%EB%86%80%EC%97%90%EC%84%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%EC%BA%90%EB%84%88-pi-alert-docker%EB%A1%9C-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9) (July 2023)
- ▶ [Pi.Alert auf Synology & Docker by - Jürgen Barth (German)](https://www.youtube.com/watch?v=-ouvA2UNu-A) (March 2023)
- ▶ [Top Docker Container for Home Server Security - VirtualizationHowto (English)](https://www.youtube.com/watch?v=tY-w-enLF6Q) (March 2023)
- ▶ [Pi.Alert or WatchYourLAN can alert you to unknown devices appearing on your WiFi or LAN network - Danie van der Merwe (English)](https://www.youtube.com/watch?v=v6an9QG2xF0) (November 2022)
> Ordered by last update time.
> Please note these might be outdated. Rely on official documentation first.
### **Common issues**
#### Common issues
💡 Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
- Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed).
- Check also common issues and [debugging tips](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEBUG_TIPS.md).
⚠ Check also common issues and [debugging tips](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
> [!NOTE]
> You can bulk-update devices via the [CSV import method](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md).
## 📄 docker-compose.yml Examples
### Example 1
```yaml
version:"3"
services:
pialert:
container_name:pialert
# use the below line if you want to test the latest dev image
# (optional) useful for debugging if you have issues setting up the container
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
environment:
- TZ=${TZ}
- HOST_USER_ID=${HOST_USER_ID}
- HOST_USER_GID=${HOST_USER_GID}
- PORT=${PORT}
```
`.env` file
```yaml
#GLOBAL PATH VARIABLES
APP_DATA_LOCATION=/path/to/docker_appdata
APP_CONFIG_LOCATION=/path/to/docker_config
LOGS_LOCATION=/path/to/docker_logs
#ENVIRONMENT VARIABLES
TZ=Europe/Paris
HOST_USER_ID=1000
HOST_USER_GID=1000
PORT=20211
#DEVELOPMENT VARIABLES
DEV_LOCATION=/path/to/local/source/code
```
To run the container execute: `sudo docker-compose --env-file /path/to/.env up`
### Example 4
Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by the db directory. The two config files are mounted directly from a local folder to their places in the config folder. You can backup the `docker-compose.yaml` folder and the docker volumes folder.
```yaml
pialert:
# use the below line if you want to test the latest dev image
- Regular updates to keep your data and family safe 🔄
- Better and more functionality➕
- I don't get burned out and the app survives longer🔥🤯
- Quicker and better support with issues 🆘
- Less grumpy me 😄
## 💙 Support me
| [](https://github.com/sponsors/jokob-sk) | [](https://www.buymeacoffee.com/jokobsk) | [](https://www.patreon.com/user?u=84385063) |
> 📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=PiAlert) if you want to get in touch or if I should add other sponsorship platforms.
> 📧 Email me at [netalertx@gmail.com](mailto:netalertx@gmail.com?subject=NetAlertX Donations) if you want to get in touch or if I should add other sponsorship platforms.
- El escaneo inicial puede tardar hasta 15 minutos (con 50 dispositivos y MQTT). Los siguientes pueden durar entre 3 y 5 minutos, así que espere a que se ejecuten todos los escaneos.
### Variables de entorno Docker
| Variable | Descripción | Predeterminado |
| :------------- |:-------------| -----:|
| `PORT` |Puerto de la interfaz web | `20211` |
|`TZ` |Zona horaria para mostrar correctamente las estadísticas. Encuentre su zona horaria [aquí](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|`HOST_USER_GID` |ID de usuario (UID) para asignar el usuario del contenedor a un usuario del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
|`HOST_USER_ID` |ID de grupo de usuarios (GID) para asignar el grupo de usuarios del contenedor a un grupo de usuarios del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
| **Obligatorio** | `:/home/pi/pialert/config` | Carpeta que contendrá el archivo `pialert.conf` (para más detalles, véase más abajo) |
| **Obligatorio** | `:/home/pi/pialert/db` | Carpeta que contendrá el archivo `pialert.db` |
|Opcional| `:/home/pi/pialert/front/log` | Carpeta de registros útil para depurar si tiene problemas al configurar el contenedor |
|Opcional| `:/etc/pihole/pihole-FTL.db` | Archivo de base de datos `pihole-FTL.db` de PiHole. Necesario si desea utilizar PiHole |
|Opcional| `:/etc/pihole/dhcp.leases` | Archivo `dhcp.leases` de PiHole. Obligatorio si desea utilizar el archivo `dhcp.leases` de PiHole. Tiene que coincidir con la correspondiente entrada de configuración `DHCPLSS_paths_to_check`. (La ruta en el contenedor debe contener `pihole`)|
|Opcional| `:/home/pi/pialert/front/api` | Una simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) que contiene archivos json estáticos (pero actualizados regularmente) y otros archivos. |
### Configurar (`pialert.conf`)
- Si no está disponible, la aplicación genera un archivo `pialert.conf` y `pialert.db` por defecto en la primera ejecución.
- La forma preferida es gestionar la configuración a través de la sección "Configuración" de la interfaz de usuario.
- Puede modificar [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directamente, si es necesario.
#### Ajustes importantes
Estos son los ajustes más importantes para obtener al menos alguna salida en la pantalla de tus Dispositivos. Por lo general, sólo se utiliza un enfoque, pero usted debe ser capaz de combinar estos enfoques.
##### Para arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
- ❗ Para usar el método arp-scan, necesitas configurar la variable `SCAN_SUBNETS`. Consulte la documentación sobre cómo [configurar SUBNETS, VLANs y limitaciones](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
##### Para pihole: PIHOLE_RUN, DHCPLSS_RUN
Hay dos maneras de importar dispositivos PiHole. A través del plugin de importación PiHole (PIHOLE) o del plugin DHCP leases (DHCPLSS).
**PiHole(Sincronización de dispositivos)**
* `PIHOLE_RUN`:Necesitas mapear `:/etc/pihole/pihole-FTL.db` en el fichero `docker-compose.yml` si activas esta opción.
**DHCPLeases (Importación de dispositivos)**
* `DHCPLSS_RUN`:Es necesario mapear `:/etc/pihole/dhcp.leases` en el fichero `docker-compose.yml` si se activa esta opción.
*La configuración anterior tiene que coincidir con una entrada de configuración correspondiente `DHCPLSS_paths_to_check` (la ruta en el contenedor debe contener `pihole` ya que PiHole utiliza un formato diferente del archivo `dhcp.leases`).
> Se recomienda utilizar el mismo intervalo de programación para todos los plugins responsables de descubrir nuevos dispositivos.
### **Problemas comunes**
💡 Antes de crear una nueva incidencia, comprueba si ya se ha resuelto una [incidencia similar](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
⚠ Compruebe también los problemas comunes y los [consejos de depuración](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
## 📄 Ejemplos
### Ejemplo 1
```yaml
version:"3"
services:
pialert:
container_name:pialert
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
# (optional) useful for debugging if you have issues setting up the container
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
environment:
- TZ=${TZ}
- HOST_USER_ID=${HOST_USER_ID}
- HOST_USER_GID=${HOST_USER_GID}
- PORT=${PORT}
```
`.env` file
```yaml
#VARIABLES DE RUTA GLOBAL
APP_DATA_LOCATION=/path/to/docker_appdata
APP_CONFIG_LOCATION=/path/to/docker_config
LOGS_LOCATION=/path/to/docker_logs
#VARIABLES DE ENTORNO
TZ=Europe/Paris
HOST_USER_ID=1000
HOST_USER_GID=1000
PORT=20211
#VARIABLES DE DESARROLLO
DEV_LOCATION=/path/to/local/source/code
```
Para ejecutar el contenedor ejecute: `sudo docker-compose --env-file /path/to/.env up`
### Example 4
Por cortesía de [pbek](https://github.com/pbek). El volumen `pialert_db` es utilizado por el directorio db. Los dos archivos de configuración se montan directamente desde una carpeta local a sus lugares en la carpeta config. Puedes hacer una copia de seguridad de la carpeta `docker-compose.yaml` y de la carpeta docker volumes.
```yaml
pialert:
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
<ahref="https://github.com/sponsors/jokob-sk"target="_blank"><imgsrc="https://i.imgur.com/X6p5ACK.png"alt="Sponsor Me on GitHub"style="height: 30px !important;width: 117px !important;"width="150px"></a>
<ahref="https://www.buymeacoffee.com/jokobsk"target="_blank"><imgsrc="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png"alt="Buy Me A Coffee"style="height: 30px !important;width: 117px !important;"width="117px"height="30px"></a>
<ahref="https://www.patreon.com/user?u=84385063"target="_blank"><imgsrc="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png"alt="Support me on patreon"style="height: 30px !important;width: 117px !important;"width="117px"></a>
PiAlert comes with a simple API. These API endpoints are static files, that are periodically updated based on your settings.
NetAlertX comes with a couple of API endpoints. All requests need to be authorized (executed in a logged in browser session) or you have to pass the value of the `API_TOKEN` settings as authorization bearer, for example:
- The `query` parameter contains the GraphQL query as a string.
- The `variables` parameter contains the input variables for the query.
2.**Query Variables**:
-`page`: Specifies the page number of results to fetch.
-`limit`: Specifies the number of results per page.
-`sort`: Specifies the sorting options, with `field` being the field to sort by and `order` being the sort order (`asc` for ascending or `desc` for descending).
-`search`: A search term to filter the devices.
-`status`: The status filter to apply (valid values are `my_devices` (determined by the `UI_MY_DEVICES` setting), `connected`, `favorites`, `new`, `down`, `archived`, `offline`).
3.**`curl` Command**:
- The `-X POST` option specifies that we are making a POST request.
- The `-H "Content-Type: application/json"` option sets the content type of the request to JSON.
- The `-d` option provides the request payload, which includes the GraphQL query and variables.
### Sample Response
The response will be in JSON format, similar to the following:
```json
{
"data":{
"devices":{
"devices":[
{
"rowid":1,
"devMac":"00:11:22:33:44:55",
"devName":"Device 1",
"devOwner":"Owner 1",
"devType":"Type 1",
"devVendor":"Vendor 1",
"devLastConnection":"2025-01-01T00:00:00Z",
"devStatus":"connected"
},
{
"rowid":2,
"devMac":"66:77:88:99:AA:BB",
"devName":"Device 2",
"devOwner":"Owner 2",
"devType":"Type 2",
"devVendor":"Vendor 2",
"devLastConnection":"2025-01-02T00:00:00Z",
"devStatus":"connected"
}
],
"count":2
}
}
}
```
## API Endpoint: JSON files
This API endpoint retrieves static files, that are periodically updated.
- Port: `20211` or as defined by the $PORT docker environment variable (same as the port for the web ui)
### When are the endpoints updated
@@ -9,7 +136,7 @@ The endpoints are updated when objects in the API endpoints are changed.
### Location of the endpoints
In the container, these files are located under the `/home/pi/pialert/front/api/` folder and thus on the `<pialert_url>/api/<File name>` url.
In the container, these files are located under the `/app/api/` folder. You can access them via the `/php/server/query_json.php?file=user_notifications.json` endpoint.
### Available endpoints
@@ -17,20 +144,16 @@ You can access the following files:
| File name | Description |
|----------------------|----------------------|
| `notification_text.txt` | The plain text version of the last notification. |
| `notification_text.html` | The full HTML of the last email notification. |
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json)). |
| `table_devices.json` | The current (at the time of the last update as mentioned above on this page) state of all of the available Devices detected by the app. |
| `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/Pi.Alert/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. |
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json)). |
| `table_devices.json` | All of the available Devices detected by the app. |
| `table_plugins_events.json` | The list of the unprocessed (pending) notification events (plugins_events DB table). |
| `table_plugins_history.json` | The list of notification events history. |
| `table_plugins_objects.json` | The content of the plugins_objects table. Find more info on the [Plugin system here](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins)|
| `table_plugins_objects.json` | The content of the plugins_objects table. Find more info on the [Plugin system here](https://github.com/jokob-sk/NetAlertX/tree/main/docs/PLUGINS.md)|
| `language_strings.json` | The content of the language_strings table, which in turn is loaded from the plugins `config.json` definitions. |
| `table_custom_endpoint.json` | A custom endpoint generated by the SQL query specified by the `API_CUSTOM_SQL` setting. |
| `table_settings.json` | The content of the settings table. |
| `app_state.json` | Contains the current application state. |
Current/latest state of the aforementioned files depends on your settings.
### JSON Data format
@@ -58,41 +181,79 @@ Example JSON of the `table_devices.json` endpoint with two Devices (database row
> To backup 99% of your configuration backup at least the `/app/config` folder. Please read the whole page (or at least "Scenario 2: Corrupted database") for details.
> Note that database definitions might change over time. The safest way is to restore your older backups into the **same version** of the app they were taken from and then gradually upgarde between releases to the latest version.
There are 4 artifacts that can be used to backup the application:
| `/db/app.db` | Database file(s) | The database file might be in an uncommitted state or corrupted |
| `/config/app.conf` | Configuration file | Can be overridden with the [`APP_CONF_OVERRIDE` env variable](https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#docker-environment-variables). |
| `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data |
| `/config/workflows.json` | A JSON file containing your workflows | N/A |
## Backup strategies
The safest approach to backups is to backup everything, by taking regular file system backups of the `/db` and `/config` folders (I use [Kopia](https://github.com/kopia/kopia)).
Arguably, the most time is spent setting up the device list, so if only one file is kept I'd recommend to have a latest backup of the `devices_<timestamp>.csv` or `devices.csv` file, followed by the `app.conf` and `workflows.json` files. You can also download `app.conf` and `devices.csv` file in the Maintenance section:

### Scenario 1: Full backup
End-result: Full restore
#### 💾 Source artifacts:
-`/app/db/app.db` (uncorrupted)
-`/app/config/app.conf`
-`/app/config/workflows.json`
#### 📥 Recovery:
To restore the application map the above files as described in the [Setup documentation](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#docker-paths).
### Scenario 2: Corrupted database
End-result: Partial restore (historical data and some plugin data will be missing)
#### 💾 Source artifacts:
-`/app/config/app.conf`
-`/app/config/devices_<timestamp>.csv` or `/app/config/devices.csv`
-`/app/config/workflows.json`
#### 📥 Recovery:
Even with a corrupted database you can recover what I would argue is 99% of the configuration.
- upload the `app.conf` and `workflows.json` files into the mounted `/app/config/` folder as described in the [Setup documentation](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#docker-paths).
- rename the `devices_<timestamp>.csv` to `devices.csv` and place it in the `/app/config` folder
- Restore the `devices.csv` backup via the [Maintenance section](./DEVICES_BULK_EDITING.md)
## Data and backup storage
To decide on a backup strategy, check where the data is stored:
### Core Configuration
The core application configuration is in the `app.conf` file (See [Settings System](./SETTINGS_SYSTEM.md) for details), such as:
- Notification settings
- Scanner settings
- Scheduled maintenance settings
- UI configuration
### Core Device Data
The core device data is backed up to the `devices_<timestamp>.csv` or `devices.csv` file via the [CSV Backup `CSVBCKP` Plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/csv_backup). This file contains data, such as:
- Device names
- Device icons
- Device network configuration
- Device categorization
- Device custom properties data
### Historical data
Historical data is stored in the `app.db` database (See [Database overview](./DATABASE.md) for details). This data includes:
- Plugin objects
- Plugin historical entries
- History of Events, Notifications, Workflow Events
Often if the application is misconfigured the `Loading...` dialog is continuously displayed. This is most likely caused by the backed failing to start. The **Maintenance -> Logs** section should give you more details on what's happening. If there is no exception, check the Portainer log, or start the container in the foreground (without the `-d` parameter) to observe any exceptions. It's advisable to enable `trace` or `debug`. Check the [Debug tips](./DEBUG_TIPS.md) on detailed instructions.
### Incorrect SCAN_SUBNETS
One of the most common issues is not configuring `SCAN_SUBNETS` correctly. If this setting is misconfigured you will only see one or two devices in your devices list after a scan. Please read the [subnets docs](./SUBNETS.md) carefully to resolve this.
### Duplicate devices and notifications
The app uses the MAC address as an unique identifier for devices. If a new MAC is detected a new device is added to the application and corresponding notifications are triggered. This means that if the MAC of an existing device changes, the device will be logged as a new device. You can usually prevent this from happening by changing the device configuration (in Android, iOS, or Windows) for your network. See the [Random Macs](./RANDOM_MAC.md) guide for details.
### Permissions
Make sure you [File permissions](./FILE_PERMISSIONS.md) are set correctly.
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/app/log`.
* To solve permission issues you can try setting the owner and group of the `app.db` by executing the following on the host system: `docker exec netalertx chown -R www-data:www-data /app/db/app.db`.
* If still facing issues, try to map the app.db file (⚠ not folder) to `:/app/db/app.db` (see [docker-compose Examples](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md#-docker-composeyml-examples) for details)
### Container restarts / crashes
* Check the logs for details. Often a required setting for a notification method is missing.
### unable to resolve host
* Check that your `SCAN_SUBNETS` variable is using the correct mask and `--interface`. See the [subnets docs for details](./SUBNETS.md).
### Invalid JSON
Check the [Invalid JSON errors debug help](./DEBUG_INVALID_JSON.md) docs on how to proceed.
### sudo execution failing (e.g.: on arpscan) on a Raspberry Pi 4
> sudo: unexpected child termination condition: 0
Resolution based on [this issue](https://github.com/linuxserver/docker-papermerge/issues/4#issuecomment-1003657581)
The link above will probably break in time too. Go to https://packages.debian.org/sid/armhf/libseccomp2/download to find the new version number and put that in the url.
### Only Router and own device show up
Make sure that the subnet and interface in `SCAN_SUBNETS` are correct. If your device/NAS has multiple ethernet ports, you probably need to change `eth0` to something else.
### Losing my settings and devices after an update
If you lose your devices and/or settings after an update that means you don't have the `/app/db` and `/app/config` folders mapped to a permanent storage. That means every time you update these folders are re-created. Make sure you have the [volumes specified correctly](./DOCKER_COMPOSE.md) in your `docker-compose.yml` or run command.
### The application is slow
Slowness is usually caused by incorrect settings (the app might restart, so check the `app.log`), too many background processes (disable unnecessary scanners), too long scans (limit the number of scanned devices), too many disk operations, or some maintenance plugins might have failed. See the [Performance tips](./PERFORMANCE.md) docs for details.
Use the official installation guides at first and use community content as supplementary material. Open an issue or PR if you'd like to add your link to the list 🙏 (Ordered by last update time)
- 📄 [How to Install NetAlertX on Your Synology NAS - Marius hosting](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
- 📄 [Using the PiAlert Network Security Scanner on a Raspberry Pi - PiMyLifeUp](https://pimylifeup.com/raspberry-pi-pialert/)
- ▶ [How to Setup Pi.Alert on Your Synology NAS - Digital Aloha](https://www.youtube.com/watch?v=M4YhpuRFaUg)
- 📄 [시놀/헤놀에서 네트워크 스캐너 Pi.Alert Docker로 설치 및 사용하기](https://blog.dalso.org/article/%EC%8B%9C%EB%86%80-%ED%97%A4%EB%86%80%EC%97%90%EC%84%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%EC%BA%90%EB%84%88-pi-alert-docker%EB%A1%9C-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9) (July 2023)
- ▶ [Pi.Alert auf Synology & Docker by - Jürgen Barth](https://www.youtube.com/watch?v=-ouvA2UNu-A) (March 2023)
- ▶ [Top Docker Container for Home Server Security - VirtualizationHowto](https://www.youtube.com/watch?v=tY-w-enLF6Q) (March 2023)
- ▶ [Pi.Alert or WatchYourLAN can alert you to unknown devices appearing on your WiFi or LAN network - Danie van der Merwe](https://www.youtube.com/watch?v=v6an9QG2xF0) (November 2022)
This functionality allows you to define **custom properties** for devices, which can store and display additional information on the device listing page. By marking properties as "Show", you can enhance the user interface with quick actions, notes, or external links.
### Key Features:
- **Customizable Properties**: Define specific properties for each device.
- **Visibility Control**: Choose which properties are displayed on the device listing page.
- **Interactive Elements**: Include actions like links, modals, and device management directly in the interface.
---
## Defining Custom Properties
Custom properties are structured as a list of objects, where each property includes the following fields:
Visible properties (`CUSTPROP_show: true`) are displayed as interactive icons in the device listing. Each icon can perform one of the following actions based on the `CUSTPROP_type`:
1.**Modals (e.g., Show Notes)**:
- Displays detailed information in a popup modal.
- Example: Firmware version details.
2.**Links**:
- Redirect to an external or internal URL.
- Example: Open a device's documentation or external site.
3.**Device Actions**:
- Manage devices with actions like delete.
- Example: Quickly remove a device from the network.
4.**Plugins**:
- Future placeholder for running custom plugin scripts.
- **Note**: Not implemented yet.
---
## Example Use Cases
1.**Device Documentation Link**:
- Add a custom property with `CUSTPROP_type` set to `link` or `link_new_tab` to allow quick navigation to the external documentation of the device.
2.**Firmware Details**:
- Use `CUSTPROP_type: show_notes` to display firmware versions or upgrade instructions in a modal.
3.**Device Removal**:
- Enable device removal functionality using `CUSTPROP_type: delete_dev`.
---
## Notes
- **Plugin Functionality**: The `run_plugin` action type is currently not implemented and will show an alert if used.
- **Custom Icons (Experimental 🧪)**: Use Base64-encoded HTML to provide custom icons for each property. You can add your icons in Setttings via the `CUSTPROP_icon` settings
- **Visibility Control**: Only properties with `CUSTPROP_show: true` will appear on the listing page.
This feature provides a flexible way to enhance device management and display with interactive elements tailored to your needs.
# A high-level description of the datbase structure
# A high-level description of the database structure
⚠ Disclaimer: As I'm not the original author, some of the information might be inaccurate. Feel free to submit a PR to correct anything within this page or documentation in general.
An overview of the most important database tables as well as an detailed overview of the Devices table. The MAC address is used as a foreign key in most cases.
The MAC address is used as a foreign key in most cases.
| `devMac` | MAC address of the device. | `00:1A:2B:3C:4D:5E` |
| `devName` | Name of the device. | `iPhone 12` |
| `devOwner` | Owner of the device. | `John Doe` |
| `devType` | Type of the device (e.g., phone, laptop, etc.). If set to a network type (e.g., switch), it will become selectable as a Network Parent Node. | `Laptop` |
| `devVendor` | Vendor/manufacturer of the device. | `Apple` |
| `devFavorite` | Whether the device is marked as a favorite. | `1` |
| `devGroup` | Group the device belongs to. | `Home Devices` |
| `devComments` | User comments or notes about the device. | `Used for work purposes` |
| `devFirstConnection` | Timestamp of the device's first connection. | `2025-03-22 12:07:26+11:00` |
| `devLastConnection` | Timestamp of the device's last connection. | `2025-03-22 12:07:26+11:00` |
| `devLastIP` | Last known IP address of the device. | `192.168.1.5` |
| `devStaticIP` | Whether the device has a static IP address. | `0` |
| `devScan` | Whether the device should be scanned. | `1` |
| `devLogEvents` | Whether events related to the device should be logged. | `0` |
| `devAlertEvents` | Whether alerts should be generated for events. | `1` |
| `devAlertDown` | Whether an alert should be sent when the device goes down. | `0` |
| `devSkipRepeated` | Whether to skip repeated alerts for this device. | `1` |
| `devLastNotification` | Timestamp of the last notification sent for this device. | `2025-03-22 12:07:26+11:00` |
| `devPresentLastScan` | Whether the device was present during the last scan. | `1` |
| `devIsNew` | Whether the device is marked as new. | `0` |
| `devLocation` | Physical or logical location of the device. | `Living Room` |
| `devIsArchived` | Whether the device is archived. | `0` |
| `devParentMAC` | MAC address of the parent device (if applicable) to build the [Network Tree](./NETWORK_TREE.md). | `00:1A:2B:3C:4D:5F` |
| `devParentPort` | Port of the parent device to which this device is connected. | `Port 3` |
| `devIcon` | [Icon](./ICONS.md) representing the device. The value is a base64-encoded SVG or Font Awesome HTML tag. | `PHN2ZyB...` |
| `devGUID` | Unique identifier for the device. | `a2f4b5d6-7a8c-9d10-11e1-f12345678901` |
| `devSite` | Site or location where the device is registered. | `Office` |
| `devSSID` | SSID of the Wi-Fi network the device is connected to. | `HomeNetwork` |
| `devSyncHubNode` | The NetAlertX node ID used for synchronization between NetAlertX instances. | `node_1` |
| `devSourcePlugin` | Source plugin that discovered the device. | `ARPSCAN` |
| `devCustomProps` | [Custom properties](./CUSTOM_PROPERTIES.md) related to the device. The value is a base64-encoded JSON object. | `PHN2ZyB...` |
To understand how values of these fields influuence application behavior, such as Notifications or Network topology, see also:
- [Device Management](./DEVICE_MANAGEMENT.md)
- [Network Tree Topology Setup](./NETWORK_TREE.md)
| CurrentScan | Result of the current scan | ![Screen1][screen1] |
| Devices | The main devices database that also contains the Network tree mappings. If `ScanCycle` is set to `0` device is not scanned. | ![Screen2][screen2] |
| Events | Used to collect connection/disconnection events. | ![Screen4][screen4] |
| Online_History | Used to display the `Device presence over time` chart | ![Screen6][screen6] |
| Online_History | Used to display the `Device presence` chart | ![Screen6][screen6] |
| Parameters | Used to pass values between the frontend and backend. | ![Screen7][screen7] |
| Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] |
| Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] |
| Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] |
| Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
| Plugins_Language_Strings | Language strings collected from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
| Sessions | Used to display sessions in the charts | ![Screen15][screen15] |
| Settings | Database representation of the sum of all settings from `pialert.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |
| Settings | Database representation of the sum of all settings from `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |
@@ -8,22 +8,27 @@ Check the the HTTP response of the failing backend call by following these steps
![F12DeveloperConsole][F12DeveloperConsole]
- Copy the URL causing the error and enter it in the address bar of your browser directly and hit enter. The copied URLs could look something like this (notice the query strings at the end):
- Post the error response in the existing issue thread on GitHub or create a new issue and include the redacted response of the failing query.
For reference, the above queries should return results in the following format:
First URL:
## First URL:
- Should yield a valid JSON file
## Second URL:
![array][array]
Second URL:
## Third URL:
![json][json]
You can copy and paste any JSON result (result of the second query) into an online JSON checker, such as [this one](https://jsonchecker.com/) to check if it's valid.
You can copy and paste any JSON result (result of the First and Third query) into an online JSON checker, such as [this one](https://jsonchecker.com/) to check if it's valid.
If a Plugin supplies data to the main app it's done either vie a SQL query or via a script that updates the `last_result.log` file in the plugin log folder (`app/log/plugins/`).
For a more in-depth overview on how plugins work check the [Plugins development docs](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md).
### Prerequisites
- Make sure you read and followed the specific plugin setup instructions.
- Ensure you have [debug enabled (see More Logging)](./DEBUG_TIPS.md)
### Potential issues
- Bugs
- Unexpected input (e.g. special characters in names)
- Dependencies changed how data is output
#### Incorrect input data
Input data from the plugin might cause mapping issues in specific edge cases. Look for a corresponding section in the `app.log` file, for example notice the first line of the execution run of the `PIHOLE` plugin below:
```
17:31:05 [Scheduler] - Scheduler run for PIHOLE: YES
17:31:05 [Plugins] CMD: SELECT n.hwaddr AS Object_PrimaryID, {s-quote}null{s-quote} AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, {s-quote}null{s-quote} AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE {s-quote}ip-%{s-quote} AND n.hwaddr is not {s-quote}00:00:00:00:00:00{s-quote} AND na.ip is not null
17:31:05 [Plugins] setTyp: subnets
17:31:05 [Plugin utils] Flattening the below array
17:31:05 [Plugins] Executing: SELECT n.hwaddr AS Object_PrimaryID, 'null' AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, 'null' AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE 'ip-%' AND n.hwaddr is not '00:00:00:00:00:00' AND na.ip is not null
17:31:06 [API] Updating table_plugins_history.json file in /api
```
> The debug output between the 🔻red arrows🔺 is important for debugging (arrows added only to highlight the section on this page, they are not available in the actual debug log)
In the above output notice the section logging how many events are produced by the plugin:
```
17:31:05 [Plugins] Existing objects from Plugins_Objects: 4
17:31:05 [Plugins] Logged events from the plugin run : 2
17:31:05 [Plugins] pluginEvents count: 2
17:31:05 [Plugins] pluginObjects count: 4
17:31:05 [Plugins] events_to_insert count: 0
17:31:05 [Plugins] history_to_insert count: 4
17:31:05 [Plugins] objects_to_insert count: 0
17:31:05 [Plugins] objects_to_update count: 4
```
These values, if formatted correctly, will also show up in the UI:
> ⚠ Please note, don't use the `-d` parameter so you see the error when the container crashes. Use this error in your issue description.
## 3. Check the _dev image and open issues ❓
## 3. Check the _dev image and open issues
If possible, check if your issue got fixed in the `_dev` image before opening a new issue. The container is:
`jokobsk/pi.alert_dev:latest`
`ghcr.io/jokob-sk/netalertx-dev:latest`
> ⚠ Please backup your DB and config beforehand!
Please also search [open issues](https://github.com/jokob-sk/Pi.Alert/issues).
Please also search [open issues](https://github.com/jokob-sk/NetAlertX/issues).
## 4. Disable restart behavior 🛑
## 4. Disable restart behavior
To prevent a Docker container from automatically restarting in a Docker Compose file, specify the restart policy as `no`:
@@ -49,36 +48,17 @@ services:
# Other service configurations...
```
## 📃Common issues
## 5. Sharing application state
### Permissions
Sometimes specific log sections are needed to debug issues. The Devices and CurrentScan table data is sometimes needed to figure out what's wrong.
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/home/pi/pialert/front/log`.
* To solve permission issues you can try setting the owner and group of the `pialert.db` by executing the following on the host system: `docker exec pialert chown -R www-data:www-data /home/pi/pialert/db/pialert.db`.
* Map to local User and Group IDs. Specify the enviroment variables `HOST_USER_ID` and `HOST_USER_GID` if needed.
* If still facing issues, try to map the pialert.db file (⚠ not folder) to `:/home/pi/pialert/db/pialert.db` (see Examples below for details)
1. Please set `LOG_LEVEL` to `trace` (Disable it once you have the info as this produces big log files).
2. Wait for the issue to occur.
3. Search for `================ DEVICES table content ================` in your logs.
4. Search for `================ CurrentScan table content ================` in your logs.
5. Open a new issue and post (redacted) output into the issue description (or send to the netalertx@gmail.com email if sensitive data present).
6. Please set `LOG_LEVEL` to `debug` or lower.
### Container restarts / crashes
## Common issues
* Check the logs for details. Often a required setting for a notification method is missing.
### unable to resolve host
* Check that your `SCAN_SUBNETS` variable is using the correct mask and `--interface` as outlined in the instructions above.
### Invalid JSON
Check the [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md) docs on how to proceed.
### sudo execution failing (e.g.: on arpscan) on a Raspberry Pi 4
> sudo: unexpected child termination condition: 0
Resolution based on [this issue](https://github.com/linuxserver/docker-papermerge/issues/4#issuecomment-1003657581)
The link above will probably break in time too. Go to https://packages.debian.org/sid/armhf/libseccomp2/download to find the new version number and put that in the url.
See [Common issues](./COMMON_ISSUES.md) for details.
NetAlertX allows you to mass-edit devices via a CSV export and import feature, or directly in the UI.
## UI multi edit
> [!NOTE]
> Make sure you have your backups saved and restorable before doing any mass edits. Check [Backup strategies](./BACKUPS.md).
You can select devices in the _Devices_ view by selecting devices to edit and then clicking the _Multi-edit_ button or via the _Maintenance_ > _Multi-Edit_ section.
The database and device structure may change with new releases. When using the CSV import functionality, ensure the format matches what the application expects. To avoid issues, you can first export the devices and review the column formats before importing any custom data.
> [!NOTE]
> As always, backup everything, just in case.
1. In `Maintenance` > `Backup / Restore` click the `CSV Export` button.
1. In _Maintenance_ > _Backup / Restore_ click the _CSV Export_ button.
2. A `devices.csv` is generated in the `/config` folder
> The file containing a list of Devices including the Network relationships between Network Nodes and connected devices. You can also trigger this by acessing this URL: `<your pialert url>/php/server/devices.php?action=ExportCSV` or via the `CSV Backup` plugin. (💡 You can schedule this)
> The file containing a list of Devices including the Network relationships between Network Nodes and connected devices. You can also trigger this by acessing this URL: `<your netalertx url>/php/server/devices.php?action=ExportCSV` or via the `CSV Backup` plugin. (💡 You can schedule this)
This set of settings allows you to group Devices under different views. The Archived toggle allows you to exclude a Device from most listings and notifications.
- Select "Devices" in the menu on the left of the screen
- Find the device you want to edit in the central table
- Go to the device page by clicking on the device name or status
- Press "Details" tab of the device
- Edit the device data
- Press the "Save" button
# NetAlertX - Device Management
The Main Info section is where most of the device identifiable information is stored and edited. Some of the information is autodetected via various plugins. Initial values for most of the fields can be specified in the `NEWDEV` plugin.
> [!NOTE]
>
> You can multi-edit devices by selecting them in the main Devices view, from the Mainetence section, or via the CSV Export functionality under Maintenance. More info can be found in the [Devices Bulk-editing docs](./DEVICES_BULK_EDITING.md).
- **MAC**: MAC addres of the device. Not editable, unless creating a new dummy device.
- **Last IP**: IP addres of the device. Not editable, unless creating a new dummy device.
- **Name**: Friendly device name. Autodetected via various 🆎 Name discovery [plugins](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md). The app attaches `(IP match)` if the name is discovered via an IP match and not MAC match which could mean the name could be incorrect as IPs might change.
- **Icon**: Partially autodetected. Select an existing or [add a custom icon](./ICONS.md). You can also auto-apply the same icon on all devices of the same type.
- **Owner**: Device owner (The list is self-populated with existing owners and you can add custom values).
- **Type**: Select a device type from the dropdown list (`Smartphone`, `Tablet`,
`Laptop`, `TV`, `router`, etc.) or add a new device type. If you want the device to act as a **Network device** (and be able to be a network node in the Network view), select a type under Network Devices or add a new Network Device type in Settings. More information can be found in the [Network Setup docs](./NETWORK_TREE.md).
- **Vendor**: The manufacturing vendor. Automatically updated by NetAlertX when empty or unknown, can be edited.
- **Group**: Select a group (`Always on`, `Personal`, `Friends`, etc.) or type
your own Group name.
- **Location**: Select the location, usually a room, where the device is located (`Kitchen`, `Attic`, `Living room`, etc.) or add a custom Location.
- **Comments**: Add any comments for the device, such as a serial number, or maintenance information.
> [!NOTE]
>
> Please note the above usage of the fields are only suggestions. You can use most of these fields for other purposes, such as storing the network interface, company owning a device, or similar.
## Dummy devices
You can create dummy devices from the Devices listing screen.
> [Bulk-edit devices](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md) by using the `CSV Export` functionality in the `Maintenance` section.
> You can couple this with the `ICMP` plugin which can be used to monitor the status of these devices, if they are actual devices reachable with the `ping` command. If not, you can use a loopback IP address so they appear online, such as `0.0.0.0` or `127.0.0.1`.
## Copying data from an existing device.
To speed up device population you can also copy data from an existing device. This can be done from the **Tools** tab on the Device details.
![Device Details][screen1]
## Main Info
- **MAC**: MAC addres of the device. Not editable.
- **Name**: Friendly device name
- **Owner**: Device owner (The list is self-populated with existing owners)
- **Type**: Select a device type from the dropdown list (Smartphone, Table,
Laptop, TV, router, ....) or type a new device type
- **Vendor**: Automatically updated by Pi.Alert when empty or unknown
- **Favorite**: Mark the device as favorite and then it will appears at the
begining of the device list
- **Group**: Select a grouper ('Always on', 'Personal', Friends') or type
your own Group name
- **Comments**: Type any comments for the device
## Session Info
- **Status**: Show device status : On-line / Off-Line
- **First Session**: Date and time of the first connection
- **Last Session**: Date and time of the last connection
- **Last IP**: Last known IP used during the last connection
- **Static IP**: Check this box to identify devices that always use the
same IP
## Events & Alerts config
- **Scan Cycle**: Select the scan cycle: 0, 1', 15'
- Some devices do not respond to all ARP packets, for this cases is better
to use a 15' cycle.
- **For Apple devices I recommend using 15' cycle**
- **Alert All Events**: Send a notification in each event (connection,
disconnection, IP Changed, ...)
- **Alert Down**: Send a notification when the device is down
- *(Userful with "always connected" devices: Router, AP, Camera, Alexa,
...)*
- **Skip repeated notifications during**: Do not send more than one
notification to this device for X hours
- *(Useful to avoid notification saturation on devices that frequently
The latest versions of some operating systems (IOS and Android) incorporate a
new & interesting functionality to improve privacy: **Random MACs**.
This functionality allows you to **hide the true MAC** of the device and
**assign a random MAC** when we connect to WIFI networks.
This behavior is especially useful when connecting to WIFI's that we do not
know, but it **is totally useless when connecting to our own WIFI's** or known
networks.
**I recommend disabling this operation when connecting our devices to our own
WIFI's**, in this way, Pi.Alert will be able to identify the device, and it
will not identify it as a new device every so often (every time IOS or Android
decides to change the MAC).
### IOS
![ios][ios]
- [Use private Wi-Fi addresses in iOS 14](https://support.apple.com/en-us/HT211227)
### Android
![Android][Android]
- [How to Disable MAC Randomization in Android 10](https://support.boingo.com/s/article/How-to-Disable-MAC-Randomization-in-Android-10-Android-Q)
- [How do I disable random Wi-Fi MAC address on Android 10](https://support.plume.com/hc/en-gb/articles/360052070714-How-do-I-disable-random-Wi-Fi-MAC-address-on-Android-10-)
### License
GPL 3.0
[Read more here](../LICENSE.txt)
### Contact
Always use the Issue tracker for the correct fork, for example:
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
> Replace `/development` with the path where your code files will be stored. The default container name is `netalertx` so there might be a conflict with your running containers.
## Development Guidelines
Before starting development, please scan the below development guidelines.
### Priority Order (Highest to Lowest)
1. 🔼 Fixing core bugs that lack workarounds.
2. 🔵 Adding core functionality that unlocks other features (e.g., plugins).
3. 🔵 Refactoring to enable faster development.
4. 🔽 UI improvements (PRs welcome).
### Design Philosophy
Focus on core functionality and integrate with existing tools rather than reinventing the wheel.
Examples:
- Using **Apprise** for notifications instead of implementing multiple separate gateways.
- Implementing **regex-based validation** instead of one-off validation for each setting.
> [!NOTE]
> UI changes have lower priority, however, PRs are welcome, but **keep them small & focused**.
> The container needs to run in `network_mode:"host"`. This also means that not all functionality is supported on a Windows host as Docker for Windows doesn't support this networking option.
### Example 1
```yaml
services:
netalertx:
container_name:netalertx
# use the below line if you want to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest"
image:"ghcr.io/jokob-sk/netalertx:latest"
network_mode:"host"
restart:unless-stopped
volumes:
- local_path/config:/app/config
- local_path/db:/app/db
# (optional) useful for debugging if you have issues setting up the container
- local_path/logs:/app/log
# (API: OPTION 1) use for performance
- type:tmpfs
target:/app/api
# (API: OPTION 2) use when debugging issues
# - local_path/api:/app/api
environment:
- TZ=Europe/Berlin
- PORT=20211
```
To run the container execute: `sudo docker-compose up -d`
### Example 2
Example by [SeimuS](https://github.com/SeimusS).
```yaml
services:
netalertx:
container_name:NetAlertX
hostname:NetAlertX
privileged:true
# use the below line if you want to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest"
image:ghcr.io/jokob-sk/netalertx:latest
environment:
- TZ=Europe/Bratislava
restart:always
volumes:
- ./netalertx/db:/app/db
- ./netalertx/config:/app/config
network_mode:host
```
To run the container execute: `sudo docker-compose up -d`
### Example 3
`docker-compose.yml`
```yaml
services:
netalertx:
container_name:netalertx
# use the below line if you want to test the latest dev image
This guide describes how to deploy **NetAlertX** in a **Docker Swarm** environment using an `ipvlan` network. This enables the container to receive a LAN IP address directly, which is ideal for network monitoring.
---
## ⚙️ Step 1: Create an IPvlan Config-Only Network on All Nodes
> Run this command on **each node** in the Swarm.
```bash
docker network create -d ipvlan \
--subnet=192.168.1.0/24 \ # 🔧 Replace with your LAN subnet
--gateway=192.168.1.1 \ # 🔧 Replace with your LAN gateway
-o ipvlan_mode=l2 \
-o parent=eno1 \ # 🔧 Replace with your network interface (e.g., eth0, eno1)
# Managing File Permissions for NetAlertX on Nginx with Docker
> [!TIP]
> If you are facing permission issues, try to start the container without mapping your volumes. If that works, then the issue is permission related. You can try e.g., the following command:
> ```
> docker run -d --rm --network=host \
> -e TZ=Europe/Berlin \
> -e PUID=200 -e PGID=200 \
> -e PORT=20211 \
> ghcr.io/jokob-sk/netalertx:latest
> ```
NetAlertX runs on an Nginx web server. On Alpine Linux, Nginx operates as the `nginx` user (if PUID and GID environment variables are not specified, nginx user UID will be set to 102, and its supplementary group `www-data` ID to 82). Consequently, files accessed or written by the NetAlertX application are owned by `nginx:www-data`.
Upon starting, NetAlertX changes nginx user UID and www-data GID to specified values (or defaults), and the ownership of files on the host system mapped to `/app/config` and `/app/db` in the container to `nginx:www-data`. This ensures that Nginx can access and write to these files. Since the user in the Docker container is mapped to a user on the host system by ID:GID, the files in `/app/config` and `/app/db` on the host system are owned by a user with the same ID and GID (defaults are ID 102 and GID 82). On different systems, this ID:GID may belong to different users, or there may not be a group with ID 82 at all.
Option to set specific user UID and GID can be useful for host system users needing to access these files (e.g., backup scripts).
### Permissions Table for Individual Folders
| Folder | User | User ID | Group | Group ID | Permissions | Notes |
| **New Devices Checkmk Script** | Checks for new devices in NetAlertX and reports status to Checkmk. | N/A | 1.0 | 08-Jan-2025 |
| **DB Cleanup Script** | Queries and removes old device-related entries from the database. | [laxduke](https://github.com/laxduke) | 1.0 | 23-Dec-2024 |
| **OPNsense DHCP Lease Converter** | Retrieves DHCP lease data from OPNsense and converts it to `dnsmasq` format. | [im-redactd](https://github.com/im-redactd) | 1.0 | 24-Feb-2025 |
## Important Notes
> [!NOTE]
> These scripts are community-supplied and not actively maintained. Use at your own discretion.
For detailed usage instructions, refer to each script's documentation in each [scripts GitHub folder](https://github.com/jokob-sk/NetAlertX/tree/main/scripts).
PiAlert 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]
> 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
- Please note that discovery takes about ~10s per device.
- Deleting of devices is not handled automatically. Please use [MQTT Explorer](https://mqtt-explorer.com/) to delete devices in the broker (Home Assistant), if needed.
- For optimization reasons, the devices are not always fully synchronized. You can delete Plugin objects as described in the [MQTT plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_mqtt#forcing-an-update) docs to force a full synchronization.
## 🧭 Guide
@@ -16,17 +20,21 @@ PiAlert comes with MQTT support, allowing you to show all detected devices as de
2. Configure a user name and password on your broker.
3. Note down the following details that you will need to configure PiAlert:
- MQTT host url (usually your Home Assistant IP)
- MQTT broker port
- User
- Password
3. Note down the following details that you will need to configure NetAlertX:
4. Ope the `PiAlert` > `Settings` > `MQTT` settings group
-Enable MQTT
-Fill in the details from above
-Fill in remaining settings as per description
- MQTT host url (usually your Home Assistant IP)
-MQTT broker port
-User
-Password
4. Open the _NetAlertX_ > _Settings_ > _MQTT_ settings group
- Enable MQTT
- Fill in the details from above
- Fill in remaining settings as per description
- set MQTT_RUN to schedule or on_notification depending on requirements
![Configuration Example][configuration]
## 📷 Screenshots
@@ -35,8 +43,50 @@ PiAlert comes with MQTT support, allowing you to show all detected devices as de
If you can't see all devices detected, run `sudo arp-scan --interface=eth0 192.168.1.0/24` (change these based on your setup, read [Subnets](./SUBNETS.md) docs for details). This command has to be executed the NetAlertX container, not in the Home Assistant container.
You can access the NetAlertX container via Portainer on your host or via ssh. The container name will be something like `addon_db21ed7f_netalertx` (you can copy the `db21ed7f_netalertx` part from the browser when accessing the UI of NetAlertX).
## Accessing the NetAlertX container via SSH
1. Log into your Home Assistant host via SSH
```bash
local@local:~ $ ssh pi@192.168.1.9
```
2. Find the NetAlertX container name, in this case `addon_db21ed7f_netalertx`
```bash
pi@raspberrypi:~ $ sudo docker container ls | grep netalertx
06c540d97f67 ghcr.io/alexbelgium/netalertx-armv7:25.3.1 "/init"6 days ago Up 6 days (healthy) addon_db21ed7f_netalertx
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.1.1 74:ac:b9:54:09:fb Ubiquiti Networks Inc.
192.168.1.21 74:ac:b9:ad:c3:30 Ubiquiti Networks Inc.
192.168.1.58 1c:69:7a:a2:34:7b EliteGroup Computer Systems Co., LTD
192.168.1.57 f4:92:bf:a3:f3:56 Ubiquiti Networks Inc.
...
```
If your result doesn't contain results similar to the above, double check your subnet, interface and if you are dealing with an inaccessible network segment, read the [Remote networks documentation](./REMOTE_NETWORKS.md).
To download and install PiAlert on the hardware/server directly use `curl` or `wget` commands.
To download and install NetAlertX on the hardware/server directly use the `curl` or `wget` commands at the bottom of this page.
> [!NOTE]
> This is an Experimental feature 🧪 and it relies on community support.
>
> 🙏 Looking for maintainers for this installation method 🙂
>
> There is no guarantee that the install script or any other script will gracefully handle other installed software.
> Data loss is a possibility, **it is recommended to install PiAlert using the supplied Docker image**.
> Data loss is a possibility, **it is recommended to install NetAlertX using the supplied Docker image**.
A warning to the installation method below: Piping to bash is [controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash) and may
be dangerous, as you cannot see the code that's about to be executed on your system.
Alternatively you can download the installation script `install/install.sh` from the repository and check the code yourself (beware other scripts are
Alternatively you can download the installation script `install/install.debian.sh` from the repository and check the code yourself (beware other scripts are
downloaded too - only from this repo).
PiAlert will be installed in `home/pi/pialert/` and run on port number `20211`.
NetAlertX will be installed in `/app` and run on port number `20211`.
Some facts about what and where something will be changed/installed by the HW install setup (may not contain everything!):
-`/home/pi/pialert` directory will be deleted and newly created
-`/home/pi/pialert` will contain the whole repository (downloaded by `install/install.sh`)
-`/app` directory will be deleted and newly created
-`/app` will contain the whole repository (downloaded by `install/install.debian.sh`)
- The default NGINX site `/etc/nginx/sites-enabled/default` will be disabled (sym-link deleted or backed up to `sites-available`)
-`/var/www/html/pialert` directory will be deleted and newly created
-`/etc/nginx/conf.d/pialert.conf` will be sym-linked to `/home/pi/pialert/install/pialert.conf`
-`/var/www/html/netalertx` directory will be deleted and newly created
-`/etc/nginx/conf.d/netalertx.conf` will be sym-linked to `/app/install/netalertx.debian.conf`
- Some files (IEEE device vendors info, ...) will be created in the directory where the installation script is executed
## Limitations
- No system service is provided. PiAlert must be started using `/home/pi/pialert/dockerfiles/start.sh`.
- No system service is provided. NetAlertX must be started using `/app/install/start.debian.sh`.
- No checks for other running software is done.
- Only tested to work on Debian Bookworm (Debian 12).
- **EXPERIMENTAL** and not recommended way to install PiAlert.
- **EXPERIMENTAL** and not recommended way to install NetAlertX.
## CURL
## 📥 Installation via CURL
> [!TIP]
> If the below fails try grabbing and installing one of the [previous releases](https://github.com/jokob-sk/NetAlertX/releases) and run the installation from the zip package.
These commands will download the `install.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.sh`.
These commands will download the `install.debian.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.debian.sh`.
Make sure you have the necessary permissions to execute the script.
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](/docs/NETWORK_TREE.md). Currently only free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0) are supported.
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](./NETWORK_TREE.md).


## ⚙ How to use custom device Icons
### Icons Support
Two types of icons are suported:
- Free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0)
- SVG icons (for example from [iconify.design](https://icon-sets.iconify.design/))
You can assign icons individually on each device in the Details tab.

1. You can get an SVG or a Font awesome HTML code
- You can click into the `Icon` field or click the Pencil (2) icon in the above screenshot to enter any text. Only [free Font Awesome](https://fontawesome.com/search?o=r&m=free) icons in the following format will work:
Copying the SVG (for example from [iconify.design](https://icon-sets.iconify.design/)):
1. For any value that is only prefixed with `fa-`, you can enter the value directly, such as `server`, `tv`, `ethernet`.
2. If you want to add another classname, e.g. `fa-brands`, you can enter `brands fa-[fontawesome-icon-name]`, so for `apple` that is using the syntax`fa-brands fa-apple`, you would enter `brands fa-apple`.
- If you want to mass-apply an icon to all devices of the same device type (Field marked (4) in the above screenshot), you can click the copy button (Marked (1) in the above screenshot). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
Copying the HTML code from [Font Awesome](https://fontawesome.com/search?o=r&m=free).
- The dropdown (3) contains all icons already used in the app for device icons. You need to navigate away or refresh the page once you add a new icon.
2. Navigate to the device you want to use the icon on and click the "+" icon:

3. Paste in the copied HTML or SVG code and click "OK":

6. "Save" the device
> [!NOTE]
> If you want to mass-apply an icon to all devices of the same device type (Field: Type), you can click the mass-copy button (next to the "+" button). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
- The dropdown contains all icons already used in the app for device icons. You might need to navigate away or refresh the page once you add a new icon.
## Font Awesome Pro icons
If you own the premium package of Font Awesome icons you can mount it in your Docker container the following way:
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] Bare metal (experimental - looking for maintainers)](https://github.com/jokob-sk/NetAlertX/blob/main/docs/HW_INSTALL.md)
## Help
If facing issues, please spend a few minutes seraching.
- Check [common issues](./COMMON_ISSUES.md)
- Have a look at [Community guides](./COMMUNITY_GUIDES.md)
- [Search closed or open issues or discussions](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue)
- Check [Discord](https://discord.gg/NczTUTWyRr)
> [!NOTE]
> If you can't find a solution anywhere, ask in Discord if you think it's a quick question, otherwise open a new [issue](https://github.com/jokob-sk/NetAlertX/issues/new?template=setup-help.yml). Please fill in as much as possible to speed up the help process.
NetAlertX comes with several logs that help to identify application issues.
For plugin-specific log debugging, please read the [Debug Plugins](./DEBUG_PLUGINS.md) guide.
When debugging any issue, increase the `LOG_LEVEL` Setting as per the [Debug tips](./DEBUG_TIPS.md) documentation.
## Main logs
You can find most of the logs exposed in the UI under _Maintenance -> Logs_.
If the UI is inaccessible, you can access them under `/app/log`.

In the _Maintennace -> Logs_ you can **Purge logs**, download the full log file or Filter the lines with some substring to narrow down your search.
## Plugin logging
If a Plugin supplies data to the main app it's done either vie a SQL query or via a script that updates the `last_result.log` file in the plugin log folder (`app/log/plugins/`). These files are processed at the end of the scan and deleted on successful processing.
The data is in most of the cases then displayed in the application under _Integrations -> Plugins_ (or _Device -> Plugins_ if the plugin is supplying device-specific data).
> Follow this guide only after you you downloaded and started NetAlert X at least once after previously using the PiAlert image.
## STEPS:
> [!TIP]
> In short: The application will auto-migrate the database, config, and all device information. A ticker message on top will be displayed until you update your docker mount points. It's always good to have a [backup strategy](./BACKUPS.md) in place.
1. Backup your current config and database (optional `devices.csv` to have a backup) (See bellow tip if facing issues)
2. Stop the container
2. Update the Docker file mount locations in your `docker-compose.yml` or docker run command (See bellow **New Docker mount locations**).
3. Rename the DB and conf files to `app.db` and `app.conf` and place them in the appropriate location.
4. Start the Container
> [!TIP]
> If you have troubles accessing past backups, config or database files you can copy them into the newly mapped directories, for example by running this command in the container: `cp -r /app/config /home/pi/pialert/config/old_backup_files`. This should create a folder in the `config` directory called `old_backup_files` conatining all the files in that location. Another approach is to map the old location and the new one at the same time to copy things over.
### New Docker mount locations
The application installation folder in the docker container has changed from `/home/pi/pialert` to `/app`. That means the new mount points are:
| Old mount point | New mount point |
|----------------------|---------------|
| `/home/pi/pialert/config` | `/app/config` |
| `/home/pi/pialert/db` | `/app/db` |
If you were mounting files directly, please note the file names have changed:
| Old file name | New file name |
|----------------------|---------------|
| `pialert.conf` | `app.conf` |
| `pialert.db` | `app.db` |
> [!NOTE]
> The application uses symlinks linking the old db and config locations to the new ones, so data loss should not occur. [Backup strategies](./BACKUPS.md) are still recommended to backup your setup.
# Examples
Examples of docker files with the new mount points.
## Example 1: Mapping folders
### Old docker-compose.yml
```yaml
services:
pialert:
container_name:pialert
# use the below line if you want to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest"
image:"jokobsk/pialert:latest"
network_mode:"host"
restart:unless-stopped
volumes:
- local/path/config:/home/pi/pialert/config
- local/path/db:/home/pi/pialert/db
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/home/pi/pialert/front/log
environment:
- TZ=Europe/Berlin
- PORT=20211
```
### New docker-compose.yml
```yaml
services:
netalertx:# ⚠ This has changed (🟡optional)
container_name:netalertx # ⚠ This has changed (🟡optional)
# use the below line if you want to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest"
image:"ghcr.io/jokob-sk/netalertx:latest"# ⚠ This has changed (🟡optional/🔺required in future)
network_mode:"host"
restart:unless-stopped
volumes:
- local/path/config:/app/config # ⚠ This has changed (🔺required)
- local/path/db:/app/db # ⚠ This has changed (🔺required)
# (optional) useful for debugging if you have issues setting up the container
- local/path/logs:/app/log # ⚠ This has changed (🟡optional)
environment:
- TZ=Europe/Berlin
- PORT=20211
```
## Example 2: Mapping files
> [!NOTE]
> The recommendation is to map folders as in Example 1, map files directly only when needed.
### Old docker-compose.yml
```yaml
services:
pialert:
container_name:pialert
# use the below line if you want to test the latest dev image
Name resolution in NetAlertX relies on multiple plugins to resolve device names from IP addresses. If you are seeing `(name not found)` as device names, follow these steps to diagnose and fix the issue.
## Required Plugins
For best results, ensure the following name resolution plugins are enabled:
- **AVAHISCAN** – Uses mDNS/Avahi to resolve local network names.
- **NBTSCAN** – Queries NetBIOS to find device names.
- **NSLOOKUP** – Performs standard DNS lookups.
You can check which plugins are active in your _Settings_ section and enable any that are missing.
There are other plugins that can supply device names as well, but they rely on bespoke hardware and services. See [Plugins overview](./PLUGINS.md) for details and look for plugins with name discovery (🆎) features.
## Checking Logs
If names are not resolving, check the logs for errors or timeouts.
See how to explore logs in the [Logging guide](./LOGGING.md).
Logs will show which plugins attempted resolution and any failures encountered.
## Adjusting Timeout Settings
If resolution is slow or failing due to timeouts, increase the timeout settings in your configuration, for example.
```ini
NSLOOKUP_RUN_TIMEOUT=30
```
Raising the timeout may help if your network has high latency or slow DNS responses.
## Checking Plugin Objects
Each plugin stores results in its respective object. You can inspect these objects to see if they contain valid name resolution data.
See [Logging guide](./LOGGING.md) and [Debug plugins](./DEBUG_PLUGINS.md) guides for details.
If the object contains no results, the issue may be with DNS settings or network access.
## Improving name resolution
For more details how to improve name resolution refer to the
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node).
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node) set to a network device type (e.g.: **Type**:`Router`).
> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/undiscoverables/README.md)
> 💡 Tip: You can add dummy devices via the [Create dummy device](./DEVICE_MANAGEMENT.md#dummy-devices) button in the Devices listing page.
> 💡 Tip: Export your configuration of the Network and Devices once in a while via the Export CSV feature under **Maintenance** -> **Backup/Restore** -> **CSV Export**.
## ⚡Quick setup:
* Go to Devices > Device Details.
*Find the device(s) you want to use as network devices (network nodes).
* Set the Type of such a device to one of the following: AP, Firewall, Gateway, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN.
* Go to a Device you want to use as network device (network nodes, such as a Switch).
*Set the **Type** of such a device to one of the following: AP, Firewall, Gateway, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN (you can create a custom network type device with in Settings -> General -> `NETWORK_DEVICE_TYPES`).
* Save and go to Network where the devices you've marked as network devices (by selecting the Type as mentioned above) will show up as tabs.
* You can now assign the Unassigend devices to the correct network node.
* If port is empty or 0 a wifi icon is rendered, otherwise a ethernet port icon
* You can now assign the Unassigend devices to the network node.
* If port is empty or 0 a wifi icon is rendered, otherwise a ethernet port icon.
> [!NOTE]
>
> [Bulk-edit devices](/docs/DEVICES_BULK_EDITING.md) by using the `CSV Export` functionality in the `Maintenance` section. You can use this to fix `Internet` node assignment issues.
> [Bulk-edit devices](./DEVICES_BULK_EDITING.md) by using the _CSV Export_ functionality in the _Maintenance_ section. You can use this to fix `Internet` node assignment issues.
## 🔍Detailed example:
@@ -28,7 +27,7 @@ In this example you will setup a device named `rapberrypi` as a `Switch` in our
- Notice the newly added `raspberrypi` (2) tab which now represents a network node, also showing up in the tree (3).
- As we asssigned the `raspberrypi` in the previous 1) Device details page section to the `Internet` parent network node in step (6), the link is also showing up in the tree diagram (4)
- As we asssigned the `raspberrypi` in the previous (1) Device details page section to the `Internet` parent network node in step (6), the link is also showing up in the tree diagram (4)
- We can now assign the device `(AppleTV)` (5) to this `raspberrypi` node, representing a network Switch in this example
### 3. Network page with 2 levels
- After clicking the `Assign` button in the previous section, the `(AppleTV)` (1) device is now connected to our `raspberrypi` (2).


- You can see the `raspberrypi` represents the Network node type `Switch` (3)
- The `(AppleTV)` to `raspberrypi` connection is also displayed in the table of `Connected devices` (4).
> It's recommended to use the same schedule interval for all plugins responsible for scanning devices, otherwise false positives might be reported if different devices are discovered by different plugins. Check the **Settings** > **Enabled settings** section for a warning:
There are 4 settings on the device for influencing notifications. You can:
1.**Alert Events** - Enables alerts of connections, disconnections, IP changes (down and down reconnected notifications are still sent even if this is disabled).
2.**Alert Down** - Alerts when a device goes down. This setting overrides a disabled **Alert Events** setting, so you will get a notification of a device going down even if you don't have **Alert Events** ticked. Disabling this will disable down and down reconnected notifications on the device.
3.**Skip repeated notifications**, if for example you know there is a temporary issue and want to pause the same notification for this device for a given time.
> [!NOTE]
> Please read through the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) documentation to understand how device and global settings influence the notification processing.
On almost all plugins there are 2 core settings, `<plugin>_WATCH` and `<plugin>_REPORT_ON`.
1.`<plugin>_WATCH` specifies the columns which the app should watch. If watched columns change the device state is considered changed. This changed status is then used to decide to send out notifications based on the `<plugin>_REPORT_ON` setting.
2.`<plugin>_REPORT_ON` let's you specify on which events the app should notify you. This is related to the `<plugin>_WATCH` setting. So if you select `watched-changed` and in `<plugin>_WATCH` you only select `Watched_Value1`, then a notification is triggered if `Watched_Value1` is changed from the previous value, but no notification is send if `Watched_Value2` changes.
Click the **Read more in the docs.** Link at the top of each plugin to get more details on how the given plugin works.
In Notification Processing settings, you can specify blanket rules. These allow you to specify exceptions to the Plugin and Device settings and will override those.
1. Notify on (`NTFPRCS_INCLUDED_SECTIONS`) allows you to specify which events trigger notifications. Usual setups will have `new_devices`, `down_devices`, and possibly `down_reconnected` set. Including `plugin` (dependenton the Plugin `<plugin>_WATCH` and `<plugin>_REPORT_ON` settings) and `events` (dependent on the on-device **Alert Events** setting) might be too noisy for most setups. More info in the [NTFPRCS plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/notification_processing/README.md) on what events these selections include.
2. Alert down after (`NTFPRCS_alert_down_time`) is useful if you want to wait for some time before the system sends out a down notification for a device. This is related to the on-device **Alert down** setting and only devices with this checked will trigger a down notification.
3. A filter to allow you to set device-specific exceptions to New devices being added to the app.
4. A filter to allow you to set device-specific exceptions to generated Events.
## Ignoring devices 🔕

You can completely ignore detected devices globally. This could be because your instance detects docker containers, you want to ignore devices from a specific manufacturer via MAC rules or you want to ignore devices on a specific IP range.
1. Ignored MACs (`NEWDEV_ignored_MACs`) - List of MACs to ignore.
2. Ignored IPs (`NEWDEV_ignored_IPs`) - List of IPs to ignore.
There are several ways to improve the application's performance. The application has been tested on a range of devices, from a Raspberry Pi 4 to NAS and NUC systems. If you are running the application on a lower-end device, carefully fine-tune the performance settings to ensure an optimal user experience.
## Common Causes of Slowness
Performance issues are usually caused by:
- **Incorrect settings** – The app may restart unexpectedly. Check `app.log` under **Maintenance → Logs** for details.
- **Too many background processes** – Disable unnecessary scanners.
- **Long scan durations** – Limit the number of scanned devices.
- **Excessive disk operations** – Optimize scanning and logging settings.
- **Increase scan intervals** (`<PLUGIN>_RUN_SCHD`) on busy networks or low-end hardware.
- **Extend scan timeouts** (`<PLUGIN>_RUN_TIMEOUT`) to prevent failures.
- **Reduce the subnet size** – e.g., from `/16` to `/24` to lower scan loads.
Some plugins have additional options to limit the number of scanned devices. If certain plugins take too long to complete, check if you can optimize scan times by selecting a scan range.
For example, the **ICMP plugin** allows you to specify a regular expression to scan only IPs that match a specific pattern.
---
## Storing Temporary Files in Memory
On systems with slower I/O speeds, you can optimize performance by storing temporary files in memory. This primarily applies to the `/app/api` and `/app/log` folders.
Using `tmpfs` reduces disk writes and improves performance. However, it should be **disabled** if persistent logs or API data storage are required.
Below is an optimized `docker-compose.yml` snippet:
```yaml
version:"3"
services:
netalertx:
container_name:netalertx
# Uncomment the line below to test the latest dev image
# image: "ghcr.io/jokob-sk/netalertx-dev:latest"
image:"ghcr.io/jokob-sk/netalertx:latest"
network_mode:"host"
restart:unless-stopped
volumes:
- local/path/config:/app/config
- local/path/db:/app/db
# (Optional) Useful for debugging setup issues
- local/path/logs:/app/log
# (API: OPTION 1) Store temporary files in memory (recommended for performance)
- type:tmpfs # ◀
target:/app/api # ◀
# (API: OPTION 2) Store API data on disk (useful for debugging)
NetAlertX comes with 2 plugins suitable for integarting with your existing PiHole instace. One plugin is using a direct SQLite DB connection, the other leverages the DHCP.leases file generated by PiHole. You can combine both approaches and also supplement it with other [plugins](/docs/PLUGINS.md).
## Approach 1: `DHCPLSS` Plugin - Import devices from the PiHole DHCP leases file
| `DHCPLSS_RUN` | When the plugin should run. | `schedule` |
| `DHCPLSS_RUN_SCHD` | If you run multiple device scanner plugins, align the schedules of all plugins to the same value. | `*/5 * * * *` |
| `DHCPLSS_paths_to_check` | You need to map the value in this setting in the `docker-compose.yml` file. The in-container path must contain `pihole` so it's parsed correctly. | `['/etc/pihole/dhcp.leases']` |
Check the [DHCPLSS plugin readme](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/dhcp_leases#overview) for details
### docker-compose changes
| Path | Description |
| :------------- | :------------- |
| `:/etc/pihole/dhcp.leases` | PiHole's `dhcp.leases` file. Required if you want to use PiHole `dhcp.leases` file. This has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole`) |
## Approach 2: `PIHOLE` Plugin - Import devices directly from the PiHole database
Check out other [plugins](/docs/PLUGINS.md) that can help you discover more about your network or check how to scan [Remote networks](./REMOTE_NETWORKS.md).
NetAlertX supports additional plugins to extend its functionality, each with its own settings and options. Plugins can be loaded via the General -> `LOADED_PLUGINS` setting. For custom plugin development, refer to the [Plugin development guide](./PLUGINS_DEV.md).
>[!NOTE]
> Please check this [Plugins debugging guide](./DEBUG_PLUGINS.md) and the corresponding Plugin documentation in the below table if you are facing issues.
## ⚡ Quick start
> [!TIP]
> You can load additional Plugins via the General -> `LOADED_PLUGINS` setting. You need to save the settings for the new plugins to load (cache/page reload may be necessary).
1. Pick your `🔍 dev scanner` plugin (e.g. `ARPSCAN` or `NMAPDEV`), or import devices into the application with an `📥 importer` plugin. (See **Enabling plugins** below)
2. Pick a `▶️ publisher` plugin, if you want to send notifications. If you don't see a publisher you'd like to use, look at the [📚_publisher_apprise](/front/plugins/_publisher_apprise/) plugin which is a proxy for over 80 notification services.
3. Setup your [Network topology diagram](./NETWORK_TREE.md)
4. Fine-tune [Notifications](./NOTIFICATIONS.md)
5. Setup [Workflows](./WORKFLOWS.md)
6. [Backup your setup](./BACKUPS.md)
7. Contribute and [Create custom plugins](./PLUGINS_DEV.md)
## Plugin types
| Plugin type | Icon | Description | When to run | Required | Data source [?](./PLUGINS_DEV.md) |
| 🔄 | Has the option to sync some data back into the plugin source |
## Available Plugins
Device-detecting plugins insert values into the `CurrentScan` database table. The plugins that are not required are safe to ignore, however, it makes sense to have at least some device-detecting plugins enabled, such as `ARPSCAN` or `NMAPDEV`.
| ID | Type | Description | Features | Required | Data source | Detailed docs |
> \* The database cleanup plugin (`DBCLNP`) is not _required_ but the app will become unusable after a while if not executed.
> ❌ marked for removal
> ⌚It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
## Enabling plugins
Plugins can be enabled via Settings, and can be disabled as needed.
1. Research which plugin you'd like to use, enable `DISCOVER_PLUGINS` and load the required plugins in Settings via the `LOADED_PLUGINS` setting.
1. Save the changes and review the Settings of the newly loaded plugins.
1. Change the `<prefix>_RUN` Setting to the recommended or custom value as per the documentation of the given setting
- If using `schedule` on a `🔍 dev scanner` plugin, make sure the schedules are the same across all `🔍 dev scanner` plugins
### Disabling, Unloading and Ignoring plugins
1. Change the `<prefix>_RUN` Setting to `disabled` if you want to disable the plugin, but keep the settings
1. If you want to speed up the application, you can unload the plugin by unselecting it in the `LOADED_PLUGINS` setting.
- Careful, once you save the Settings Unloaded plugin settings will be lost (old `app.conf` files are kept in the `/config` folder)
1. You can completely ignore plugins by placing a `ignore_plugin` file into the plugin directory. Ignored plugins won't show up in the `LOADED_PLUGINS` setting.
## 🆕 Developing new custom plugins
If you want to develop a custom plugin, please read this [Plugin development guide](./PLUGINS_DEV.md).
NetAlertX comes with a plugin system to feed events from third-party scripts into the UI and then send notifications, if desired. The highlighted core functionality this plugin system supports, is:
* dynamic creation of a simple UI to interact with the discovered objects,
* filtering of displayed values in the Devices UI
* surface settings of plugins in the UI,
* different column types for reported values to e.g. link back to a device
* import objects into existing NetAlertX database tables
> (Currently, update/overwriting of existing objects is only supported for devices via the `CurrentScan` table.)
### 🎥 Watch the video:
> [!TIP]
> Read this guide [Development environment setup guide](./DEV_ENV_SETUP.md) to set up your local environment for development. 👩💻
[](https://youtu.be/cdbxlwiWhv8)
* Import devices from dhcp.leases files instead/complementary to using PiHole or arp-scans
* Creating ad-hoc UI tables from existing data in the NetAlertX database, e.g. to show all open ports on devices, to list devices that disconnected in the last hour, etc.
* Using other device discovery methods on the network and importing the data as new devices
* Creating a script to create FAKE devices based on user input via custom settings
* ...at this point the limitation is mostly the creativity rather than the capability (there might be edge cases and a need to support more form controls for user input off custom settings, but you probably get the idea)
If you wish to develop a plugin, please check the existing plugin structure. Once the settings are saved by the user they need to be removed from the `app.conf` file manually if you want to re-initialize them from the `config.json` of the plugin.
## ⚠ Disclaimer
Please read the below carefully if you'd like to contribute with a plugin yourself. This documentation file might be outdated, so double-check the sample plugins as well.
## Plugin file structure overview
> ⚠️Folder name must be the same as the code name value in: `"code_name": "<value>"`
> Unique prefix needs to be unique compared to the other settings prefixes, e.g.: the prefix `APPRISE` is already in use.
| `config.json` | yes | Contains the plugin configuration (manifest) including the settings available to the user. |
| `script.py` | no | The Python script itself. You may call any valid linux command. |
| `last_result.<prefix>.log` | no | The file used to interface between NetAlertX and the plugin. Required for a script plugin if you want to feed data into the app. Stored in the `/api/log/plugins/` |
| `script.log` | no | Logging output (recommended) |
| `README.md` | yes | Any setup considerations or overview |
More on specifics below.
### Column order and values (plugins interface contract)
> [!IMPORTANT]
> Spend some time reading and trying to understand the below table. This is the interface between the Plugins and the core application. The application expets 9 or 13 values The first 9 values are mandatory. The next 4 values (`HelpVal1` to `HelpVal4`) are optional. However, if you use any of these optional values (e.g., `HelpVal1`), you need to supply all optional values (e.g., `HelpVal2`, `HelpVal3`, and `HelpVal4`). If a value is not used, it should be padded with `null`.
| Order | Represented Column | Value Required | Description |
| 0 | `Object_PrimaryID` | yes | The primary ID used to group Events under. |
| 1 | `Object_SecondaryID` | no | Optional secondary ID to create a relationship beween other entities, such as a MAC address |
| 2 | `DateTime` | yes | When the event occured in the format `2023-01-02 15:56:30` |
| 3 | `Watched_Value1` | yes | A value that is watched and users can receive notifications if it changed compared to the previously saved entry. For example IP address |
| 4 | `Watched_Value2` | no | As above |
| 5 | `Watched_Value3` | no | As above |
| 6 | `Watched_Value4` | no | As above |
| 7 | `Extra` | no | Any other data you want to pass and display in NetAlertX and the notifications |
| 8 | `ForeignKey` | no | A foreign key that can be used to link to the parent object (usually a MAC address) |
| 9 | `HelpVal1` | no | (optional) A helper value |
| 10 | `HelpVal2` | no | (optional) A helper value |
| 11 | `HelpVal3` | no | (optional) A helper value |
| 12 | `HelpVal4` | no | (optional) A helper value |
> [!NOTE]
> De-duplication is run once an hour on the `Plugins_Objects` database table and duplicate entries with the same value in columns `Object_PrimaryID`, `Object_SecondaryID`, `Plugin` (auto-filled based on `unique_prefix` of the plugin), `UserData` (can be populated with the `"type": "textbox_save"` column type) are removed.
# config.json structure
The `config.json` file is the manifest of the plugin. It contains mainly settings definitions and the mapping of Plugin objects to NetAlertX objects.
## Execution order
The execution order is used to specify when a plugin is executed. This is useful if a plugin has access and surfaces more information than others. If a device is detected by 2 plugins and inserted into the `CurrentScan` table, the plugin with the higher priority (e.g.: `Level_0` is a higher priority than `Level_1`) will insert it's values first. These values (devices) will be then prioritized over any values inserted later.
```json
{
"execution_order":"Layer_0"
}
```
## Supported data sources
Currently, these data sources are supported (valid `data_source` value).
| Name | `data_source` value | Needs to return a "table"* | Overview (more details on this page below) |
| Script | `script` | no | Executes any linux command in the `CMD` setting. |
| NetAlertX DB query | `app-db-query` | yes | Executes a SQL query on the NetAlertX database in the `CMD` setting. |
| Template | `template` | no | Used to generate internal settings, such as default values. |
| External SQLite DB query | `sqlite-db-query` | yes | Executes a SQL query from the `CMD` setting on an external SQLite database mapped in the `DB_PATH` setting. |
| Plugin type | `plugin_type` | no | Specifies the type of the plugin and in which section the Plugin settings are displayed ( one of `general/system/scanner/other/publisher` ). |
> * "Needs to return a "table" means that the application expects a `last_result.<prefix>.log` file with some results. It's not a blocker, however warnings in the `app.log` might be logged.
> 🔎Example
>```json
>"data_source": "app-db-query"
>```
If you want to display plugin objects or import devices into the app, data sources have to return a "table" of the exact structure as outlined above.
You can show or hide the UI on the "Plugins" page and "Plugins" tab for a plugin on devices via the `show_ui` property:
> 🔎Example
>```json
> "show_ui": true,
> ```
### "data_source": "script"
If the `data_source` is set to `script` the `CMD` setting (that you specify in the `settings` array section in the `config.json`) contains an executable Linux command, that usually generates a `last_result.<prefix>.log` file (not required if you don't import any data into the app). The `last_result.<prefix>.log` file needs to be saved in `/api/log/plugins`.
> [!IMPORTANT]
> A lot of the work is taken care of by the [`plugin_helper.py` library](/front/plugins/plugin_helper.py). You don't need to manage the `last_result.<prefix>.log` file if using the helper objects. Check other `script.py` of other plugins for details.
The content of the `last_result.<prefix>.log` file needs to contain the columns as defined in the "Column order and values" section above. The order of columns can't be changed. After every scan it should contain only the results from the latest scan/execution.
- The format of the `last_result.<prefix>.log` is a `csv`-like file with the pipe `|` as a separator.
- 9 (nine) values need to be supplied, so every line needs to contain 8 pipe separators. Empty values are represented by `null`.
- Don't render "headers" for these "columns".
Every scan result/event entry needs to be on a new line.
- You can find which "columns" need to be present, and if the value is required or optional, in the "Column order and values" section.
If the `data_source` is set to `app-db-query`, the `CMD` setting needs to contain a SQL query rendering the columns as defined in the "Column order and values" section above. The order of columns is important.
This SQL query is executed on the `app.db` SQLite database file.
> 🔎Example
>
> SQL query example:
>
> ```SQL
> SELECT dv.devName as Object_PrimaryID,
> cast(dv.devLastIP as VARCHAR(100)) || ':' || cast( SUBSTR(ns.Port ,0, INSTR(ns.Port , '/')) as VARCHAR(100)) as Object_SecondaryID,
> datetime() as DateTime,
> ns.Service as Watched_Value1,
> ns.State as Watched_Value2,
> 'null' as Watched_Value3,
> 'null' as Watched_Value4,
> ns.Extra as Extra,
> dv.devMac as ForeignKey
> FROM
> (SELECT * FROM Nmap_Scan) ns
> LEFT JOIN
> (SELECT devName, devMac, devLastIP FROM Devices) dv
> ON ns.MAC = dv.devMac
> ```
>
> Required `CMD` setting example with above query (you can set `"type": "label"` if you want it to make uneditable in the UI):
> "default_value":"SELECT dv.devName as Object_PrimaryID, cast(dv.devLastIP as VARCHAR(100)) || ':' || cast( SUBSTR(ns.Port ,0, INSTR(ns.Port , '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, ns.Service as Watched_Value1, ns.State as Watched_Value2, 'null' as Watched_Value3, 'null' as Watched_Value4, ns.Extra as Extra FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT devName, devMac, devLastIP FROM Devices) dv ON ns.MAC = dv.devMac",
> "options": [],
> "localized": ["name", "description"],
> "name" : [{
> "language_code":"en_us",
> "string" : "SQL to run"
> }],
> "description": [{
> "language_code":"en_us",
> "string" : "This SQL query is used to populate the coresponding UI tables under the Plugins section."
> }]
> }
> ```
### "data_source": "template"
In most cases, it is used to initialize settings. Check the `newdev_template` plugin for details.
### "data_source": "sqlite-db-query"
You can execute a SQL query on an external database connected to the current NetAlertX database via a temporary `EXTERNAL_<uniqueprefix>.` prefix.
For example for `PIHOLE` (`"unique_prefix": "PIHOLE"`) it is `EXTERNAL_PIHOLE.`. The external SQLite database file has to be mapped in the container to the path specified in the `DB_PATH` setting:
> "string" : "Required setting for the <code>sqlite-db-query</code> plugin type. Is used to mount an external SQLite database and execute the SQL query stored in the <code>CMD</code> setting."
> }]
> }
> ...
>```
The actual SQL query you want to execute is then stored as a `CMD` setting, similar to a Plugin of the `app-db-query` plugin type. The format has to adhere to the format outlined in the "Column order and values" section above.
> "default_value":"SELECT hwaddr as Object_PrimaryID, cast('http://' || (SELECT ip FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1) as VARCHAR(100)) || ':' || cast( SUBSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1), 0, INSTR((SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1), '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, macVendor as Watched_Value1, lastQuery as Watched_Value2, (SELECT name FROM EXTERNAL_PIHOLE.network_addresses WHERE network_id = id ORDER BY lastseen DESC, ip LIMIT 1) as Watched_Value3, 'null' as Watched_Value4, '' as Extra, hwaddr as ForeignKey FROM EXTERNAL_PIHOLE.network WHERE hwaddr NOT LIKE 'ip-%' AND hwaddr <> '00:00:00:00:00:00'; ",
> "options": [],
> "localized": ["name", "description"],
> "name" : [{
> "language_code":"en_us",
> "string" : "SQL to run"
> }],
> "description": [{
> "language_code":"en_us",
> "string" : "This SQL query is used to populate the coresponding UI tables under the Plugins section. This particular one selects data from a mapped PiHole SQLite database and maps it to the corresponding Plugin columns."
> }]
> }
> ```
## 🕳 Filters
Plugin entries can be filtered in the UI based on values entered into filter fields. The `txtMacFilter` textbox/field contains the Mac address of the currently viewed device, or simply a Mac address that's available in the `mac` query string (`<url>?mac=aa:22:aa:22:aa:22:aa`).
>2. This input field is initialized via the `&mac=` query string.
>
>3. The app then proceeds to use this Mac value from this field and compares it to the value of the `Object_PrimaryID` database field. The `compare_operator` is `==`.
>
>4. Both values, from the database field `Object_PrimaryID` and from the `txtMacFilter` are wrapped and evaluated with the `compare_js_template`, that is `'{value}.toString()'`.
>
>5. `compare_use_quotes` is set to `true` so `'{value}'.toString()` is wrappe dinto `"` quotes.
>
>6. This results in for example this code:
>
>```javascript
> // left part of the expression coming from compare_column and right from the input field
> // notice the added quotes ()") around the left and right part of teh expression
### 🗺 Mapping the plugin results into a database table
Plugin results are always inserted into the standard `Plugin_Objects` database table. Optionally, NetAlertX can take the results of the plugin execution, and insert these results into an additional database table. This is enabled by with the property `"mapped_to_table"` in the `config.json` file. The mapping of the columns is defined in the `database_column_definitions` array.
> [!NOTE]
> If results are mapped to the `CurrentScan` table, the data is then included into the regular scan loop, so for example notification for devices are sent out.
>🔍 Example:
>
>For example, this approach is used to implement the `DHCPLSS` plugin. The script parses all supplied "dhcp.leases" files, gets the results in the generic table format outlined in the "Column order and values" section above, takes individual values, and inserts them into the `CurrentScan` database table in the NetAlertX database. All this is achieved by:
>
>1. Specifying the database table into which the results are inserted by defining `"mapped_to_table": "CurrentScan"` in the root of the `config.json` file as shown below:
>2. Defining the target column with the `mapped_to_column` property for individual columns in the `database_column_definitions` array of the `config.json` file. For example in the `DHCPLSS` plugin, I needed to map the value of the `Object_PrimaryID` column returned by the plugin, to the `cur_MAC` column in the NetAlertX database table `CurrentScan`. Notice the `"mapped_to_column": "cur_MAC"` key-value pair in the sample below.
>
>```json
>{
> "column": "Object_PrimaryID",
> "mapped_to_column": "cur_MAC",
> "css_classes": "col-sm-2",
> "show": true,
> "type": "device_mac",
> "default_value":"",
> "options": [],
> "localized": ["name"],
> "name":[{
> "language_code":"en_us",
> "string" : "MAC address"
> }]
> }
>```
>
>3. That's it. The app takes care of the rest. It loops thru the objects discovered by the plugin, takes the results line-by-line, and inserts them into the database table specified in `"mapped_to_table"`. The columns are translated from the generic plugin columns to the target table columns via the `"mapped_to_column"` property in the column definitions.
> [!NOTE]
> You can create a column mapping with a default value via the `mapped_to_column_data` property. This means that the value of the given column will always be this value. That also means that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
>🔍 Example:
>
>```json
>{
> "column": "NameDoesntMatter",
> "mapped_to_column": "cur_ScanMethod",
> "mapped_to_column_data": {
> "value": "DHCPLSS"
> },
> "css_classes": "col-sm-2",
> "show": true,
> "type": "device_mac",
> "default_value":"",
> "options": [],
> "localized": ["name"],
> "name":[{
> "language_code":"en_us",
> "string" : "MAC address"
> }]
> }
>```
#### params
> [!IMPORTANT]
> An esier way to access settings in scripts is the `get_setting_value` method.
> ```python
> from helper import get_setting_value
>
> ...
> NTFY_TOPIC = get_setting_value('NTFY_TOPIC')
> ...
>
> ```
The `params` array in the `config.json` is used to enable the user to change the parameters of the executed script. For example, the user wants to monitor a specific URL.
> 🔎 Example:
> Passing user-defined settings to a command. Let's say, you want to have a script, that is called with a user-defined parameter called `urls`:
* You can allow the user to add URLs to a setting with the `function` property set to a custom name, such as `urls_to_check` (this is not a reserved name from the section "Supported settings `function` values" below).
* You specify the parameter `urls` in the `params` section of the `config.json` the following way (`WEBMON_` is the plugin prefix automatically added to all the settings):
```json
{
"params" : [
{
"name" : "urls",
"type" : "setting",
"value" : "WEBMON_urls_to_check"
}]
}
```
* Then you use this setting as an input parameter for your command in the `CMD` setting. Notice `urls={urls}` in the below json:
During script execution, the app will take the command `"python3 /app/front/plugins/website_monitor/script.py urls={urls}"`, take the `{urls}` wildcard and replace it with the value from the `WEBMON_urls_to_check` setting. This is because:
1. The app checks the `params` entries
2. It finds `"name" : "urls"`
3. Checks the type of the `urls` params and finds `"type" : "setting"`
4. Gets the setting name from `"value" : "WEBMON_urls_to_check"`
- IMPORTANT: in the `config.json` this setting is identified by `"function":"urls_to_check"`, not `"function":"WEBMON_urls_to_check"`
- You can also use a global setting, or a setting from a different plugin
5. The app gets the user defined value from the setting with the code name `WEBMON_urls_to_check`
- let's say the setting with the code name `WEBMON_urls_to_check` contains 2 values entered by the user:
Below are some general additional notes, when defining `params`:
- `"name":"name_value"` - is used as a wildcard replacement in the `CMD` setting value by using curly brackets `{name_value}`. The wildcard is replaced by the result of the `"value" : "param_value"` and `"type":"type_value"` combo configuration below.
- `"type":"<sql|setting>"` - is used to specify the type of the params, currently only 2 supported (`sql`,`setting`).
- `"type":"sql"` - will execute the SQL query specified in the `value` property. The sql query needs to return only one column. The column is flattened and separated by commas (`,`), e.g: `SELECT devMac from DEVICES` -> `Internet,74:ac:74:ac:74:ac,44:44:74:ac:74:ac`. This is then used to replace the wildcards in the `CMD` setting.
- `"type":"setting"` - The setting code name. A combination of the value from `unique_prefix` + `_` + `function` value, or otherwise the code name you can find in the Settings page under the Setting display name, e.g. `PIHOLE_RUN`.
- `"value": "param_value"` - Needs to contain a setting code name or SQL query without wildcards.
- `"timeoutMultiplier" : true` - used to indicate if the value should multiply the max timeout for the whole script run by the number of values in the given parameter.
- `"base64": true` - use base64 encoding to pass the value to the script (e.g. if there are spaces)
> 🔎Example:
>
> ```json
> {
> "params" : [{
> "name" : "ips",
> "type" : "sql",
> "value" : "SELECT devLastIP from DEVICES",
> "timeoutMultiplier" : true
> },
> {
> "name" : "macs",
> "type" : "sql",
> "value" : "SELECT devMac from DEVICES"
> },
> {
> "name" : "timeout",
> "type" : "setting",
> "value" : "NMAP_RUN_TIMEOUT"
> },
> {
> "name" : "args",
> "type" : "setting",
> "value" : "NMAP_ARGS",
> "base64" : true
> }]
> }
> ```
#### ⚙ Setting object structure
> [!NOTE]
> The settings flow and when Plugin specific settings are applied is described under the [Settings system](./SETTINGS_SYSTEM.md).
Required attributes are:
| Property | Description |
| -------- | ----------- |
| `"function"` | Specifies the function the setting drives or a simple unique code name. See Supported settings function values for options. |
| `"type"` | Specifies the form control used for the setting displayed in the Settings page and what values are accepted. Supported options include: |
| `"localized"` | A list of properties on the current JSON level that need to be localized. |
| `"name"` | Displayed on the Settings page. An array of localized strings. See Localized strings below. |
| `"description"` | Displayed on the Settings page. An array of localized strings. See Localized strings below. |
| (optional) `"events"` | Specifies whether to generate an execution button next to the input field of the setting. Supported values: |
| | - `"test"` - For notification plugins testing |
| | - `"run"` - Regular plugins testing |
| (optional) `"override_value"` | Used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (Work in progress) |
| (optional) `"events"` | Used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting. After clicking, an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. |
### UI Component Types Documentation
This section outlines the structure and types of UI components, primarily used to build HTML forms or interactive elements dynamically. Each UI component has a `"type"` which defines its structure, behavior, and rendering options.
#### UI Component JSON Structure
The UI component is defined as a JSON object containing a list of `elements`. Each element specifies how it should behave, with properties like `elementType`, `elementOptions`, and any associated `transformers` to modify the data. The example below demonstrates how a component with two elements (`span` and `select`) is structured:
The code snippet provided demonstrates how the elements are iterated over to generate their corresponding HTML. Depending on the `elementType`, different HTML tags (like `<select>`, `<input>`, `<textarea>`, `<button>`, etc.) are created with the respective attributes such as `onChange`, `my-data-type`, and `class` based on the provided `elementOptions`. Events can also be attached to elements like buttons or select inputs.
### Key Element Types
- **`select`**: Renders a dropdown list. Additional options like `isMultiSelect` and event handlers (e.g., `onChange`) can be attached.
- **`input`**: Handles various types of input fields, including checkboxes, text, and others, with customizable attributes like `readOnly`, `placeholder`, etc.
- **`button`**: Generates clickable buttons with custom event handlers (`onClick`), icons, or labels.
- **`textarea`**: Creates a multi-line input box for text input.
- **`span`**: Used for inline text or content with customizable classes and data attributes.
Each element may also have associated events (e.g., running a scan or triggering a notification) defined under `Events`.
##### Supported settings `function` values
You can have any `"function": "my_custom_name"` custom name, however, the ones listed below have a specific functionality attached to them.
| Setting | Description |
| ------- | ----------- |
| `RUN` | (required) Specifies when the service is executed. |
| | Supported Options: |
| | - "disabled" - do not run |
| | - "once" - run on app start or on settings saved |
| | - "schedule" - if included, then a `RUN_SCHD` setting needs to be specified to determine the schedule |
| | - "always_after_scan" - run always after a scan is finished |
| | - "before_name_updates" - run before device names are updated (for name discovery plugins) |
| | - "on_new_device" - run when a new device is detected |
| | - "before_config_save" - run before the config is marked as saved. Useful if your plugin needs to modify the `app.conf` file. |
| `RUN_SCHD` | (required if you include "schedule" in the above `RUN` function) Cron-like scheduling is used if the `RUN` setting is set to `schedule`. |
| `CMD` | (required) Specifies the command that should be executed. |
| `API_SQL` | (not implemented) Generates a `table_` + `code_name` + `.json` file as per [API docs](./API.md). |
| `RUN_TIMEOUT` | (optional) Specifies the maximum execution time of the script. If not specified, a default value of 10 seconds is used to prevent hanging. |
| `WATCH` | (optional) Specifies which database columns are watched for changes for this particular plugin. If not specified, no notifications are sent. |
| `REPORT_ON` | (optional) Specifies when to send a notification. Supported options are: |
| | - `new` means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. |
| | - `watched-changed` - means that selected `Watched_ValueN` columns changed |
| | - `watched-not-changed` - reports even on events where selected `Watched_ValueN` did not change |
| | - `missing-in-last-scan` - if the object is missing compared to previous scans |
> "string" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_RUN_TIMEOUT\"><code>WEBMON_RUN_TIMEOUT</code> setting</a>."
> }]
> }
> ```
##### 🌍Localized strings
- `"language_code":"<en_us|es_es|de_de>"` - code name of the language string. Only these three are currently supported. At least the `"language_code":"en_us"` variant has to be defined.
- `"string"` - The string to be displayed in the given language.
> 🔎 Example:
>
> ```json
>
> {
> "language_code":"en_us",
> "string" : "When to run"
> }
>
> ```
##### UI settings in database_column_definitions
The UI will adjust how columns are displayed in the UI based on the resolvers definition of the `database_column_definitions` object. These are the supported form controls and related functionality:
- Only columns with `"show": true` and also with at least an English translation will be shown in the UI.
| Supported Types | Description |
| -------------- | ----------- |
| `label` | Displays a column only. |
| `textarea_readonly` | Generates a read only text area and cleans up the text to display it somewhat formatted with new lines preserved. |
| See below for information on `threshold`, `replace`. | |
| | |
| `options` Property | Used in conjunction with types like `threshold`, `replace`, `regex`. |
| `options_params` Property | Used in conjunction with a `"options": "[{value}]"` template and `text.select`/`list.select`. Can specify SQL query (needs to return 2 columns `SELECT devName as name, devMac as id`) or Setting (not tested) to populate the dropdown. Check example below or have a look at the `NEWDEV` plugin `config.json` file. |
| `threshold` | The `options` array contains objects ordered from the lowest `maximum` to the highest. The corresponding `hexColor` is used for the value background color if it's less than the specified `maximum` but more than the previous one in the `options` array. |
| `replace` | The `options` array contains objects with an `equals` property, which is compared to the "value." If the values are the same, the string in `replacement` is displayed in the UI instead of the actual "value". |
| `regex` | Applies a regex to the value. The `options` array contains objects with an `type` (must be set to `regex`) and `param` (must contain the regex itself) property. |
| | |
| Type Definitions | |
| `device_mac` | The value is considered to be a MAC address, and a link pointing to the device with the given MAC address is generated. |
| `device_ip` | The value is considered to be an IP address. A link pointing to the device with the given IP is generated. The IP is checked against the last detected IP address and translated into a MAC address, which is then used for the link itself. |
| `device_name_mac` | The value is considered to be a MAC address, and a link pointing to the device with the given MAC is generated. The link label is resolved as the target device name. |
| `url` | The value is considered to be a URL, so a link is generated. |
| `textbox_save` | Generates an editable and saveable text box that saves values in the database. Primarily intended for the `UserData` database column in the `Plugins_Objects` table. |
| `url_http_https` | Generates two links with the `https` and `http` prefix as lock icons. |
| `eval` | Evaluates as JavaScript. Use the variable `value` to use the given column value as input (e.g. `'<b>${value}<b>'` (replace ' with ` in your code) ) |
> [!NOTE]
> Supports chaining. You can chain multiple resolvers with `.`. For example `regex.url_http_https`. This will apply the `regex` resolver and then the `url_http_https` resolver.
"value":"SELECT '' as id, '' as name UNION SELECT devType as id, devType as name FROM (SELECT devType FROM Devices UNION SELECT 'Smartphone' UNION SELECT 'Tablet' UNION SELECT 'Laptop' UNION SELECT 'PC' UNION SELECT 'Printer' UNION SELECT 'Server' UNION SELECT 'NAS' UNION SELECT 'Domotic' UNION SELECT 'Game Console' UNION SELECT 'SmartTV' UNION SELECT 'Clock' UNION SELECT 'House Appliance' UNION SELECT 'Phone' UNION SELECT 'AP' UNION SELECT 'Gateway' UNION SELECT 'Firewall' UNION SELECT 'Switch' UNION SELECT 'WLAN' UNION SELECT 'Router' UNION SELECT 'Other') AS all_devices ORDER BY id;"
The latest versions of some operating systems (IOS and Android) incorporate a
new & interesting functionality to improve privacy: **Random MACs**.
Some operating systems incorporate randomize MAC addresses to improve privacy.
This functionality allows you to **hide the real MAC** of the device and
**assign a random MAC** when we connect to WIFI networks.
This functionality allows you to **hide the real MAC** of the device and**assign a random MAC** when we connect to WIFI networks.
This behavior is especially useful when connecting to WIFI's that we do not
know, but it **is totally useless when connecting to our own WIFI's** or known
networks.
This behavior is especially useful when connecting to WIFI's that we do not know, but it **is totally useless when connecting to our own WIFI's** or known networks.
**I recommend disabling this operation when connecting our devices to our own
WIFI's**, in this way, Pi.Alert will be able to identify the device, and it
will not identify it as a new device every so often (every time IOS or Android
decides to change the MAC).
**I recommend disabling this on-device functionality when connecting our devices to our own WIFI's**, this way, NetAlertX will be able to identify the device, and it will not identify it as a new device every so often (every time iOS or Android randomizes the MAC).
**Random MACs** are recognized by the characters "2", "6", "A", or "E" as the 2nd character in the Mac address. You can disable specific prefixes to be detected as random MAC addresses by specifying the `UI_NOT_RANDOM_MAC` setting.
- [How to Disable MAC Randomization on Windows](https://www.androidphonesoft.com/blog/how-to-turn-off-random-mac-address-windows-10/)
## IOS
![ios][ios]

- [Use private Wi-Fi addresses in iOS 14](https://support.apple.com/en-us/HT211227)
## Android
![Android][Android]

- [How to Disable MAC Randomization in Android 10](https://support.boingo.com/s/article/How-to-Disable-MAC-Randomization-in-Android-10-Android-Q)
- [How do I disable random Wi-Fi MAC address on Android 10](https://support.plume.com/hc/en-gb/articles/360052070714-How-do-I-disable-random-Wi-Fi-MAC-address-on-Android-10-)
### License
GPL 3.0
[Read more here](../LICENSE.txt)
### Contact
Always use the Issue tracker for the correct fork, for example:
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
In the app hover over settings or fields/labels or click blue in-app ❔ (question-mark) icons to get to relevant documentation pages.
<details>
<summary>:information_source: In the app hover over settings or fields/labels or click blue in-app ❔ (question-mark) icons to get to relevant documentation pages.</summary>


</details>
There is also an in-app Help / FAQ section that should be answering frequently asked questions.
### 📥 Installation
⚠ Only tested as a [docker container - follow these instructions here](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md).
> Check out [leiweibau's fork](https://github.com/leiweibau/Pi.Alert/) if you want to install Pi.Alert on the server directly or original instructions for [pucherot's original code](https://github.com/pucherot/Pi.Alert/)
#### 🐳 Docker (Fully supported)
- The main installation method is as a [docker container - follow these instructions here](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md).
Design philosophy: Focus on core functionality and leverage existing apps and tools to make PiAlert integrate into other workflows.
Design philosophy: Focus on core functionality and leverage existing apps and tools to make NetAlertX integrate into other workflows.
Examples:
@@ -88,7 +115,7 @@ If you submit a PR please:
1. Check that your changes are backward compatible with existing installations and with a blank setup.
2. Existing features should always be preserved.
3. Keep the PR small, on-topic and don't change code that is not necessary for the PR to work
4. New features code should ideally be re-usable for different purposes, not be for a very narrow use-case.
4. New features code should ideally be re-usable for different purposes, not for a very narrow usecase.
5. New functionality should ideally be implemented via the Plugins system, if possible.
Suggested test cases:
@@ -96,22 +123,22 @@ Suggested test cases:
- Blank setup with no DB or config
- Existing DB / config
- Sending a notification (e. g. Delete a device and wait for a scan to run) and testing all notification gateways, especially:
- Email, Apprise (e.g. via Telegram), webhook (e.g. via Discord), MQTT (e.g. via HomeAssitant)
- Email, Apprise (e.g. via Telegram), webhook (e.g. via Discord), MQTT (e.g. via HomeAssistant)
- Saving settings
- Test a couple of plugins
- Check the Error log for anything unusual
Some additional context:
* Permanent settings/config is stored in the `pialert.conf` file
* Permanent settings/config is stored in the `app.conf` file
* Currently temporary (session?) settings are stored in the `Parameters` DB table as key-value pairs. This table is wiped during a container rebuild/restart and its values are re-initialized from cookies/session data from the browser.
## 🐛 Submitting an issue or bug
Before submitting a new issue please spend a couple of minutes on research:
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/tree/main/dockerfiles#-common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* When submitting an issue ❗[enable debug](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)❗
* Check [🛑 Common issues](./DEBUG_TIPS.md#common-issues)
* Check [💡 Closed issues](https://github.com/jokob-sk/NetAlertX/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
* When submitting an issue ❗[enable debug](./DEBUG_TIPS.md)❗
⚠ Please follow the pre-defined issue template to resolve your issue faster.
By design, local network scanners such as `arp-scan` use ARP (Address Resolution Protocol) to map IP addresses to MAC addresses on the local network. Since ARP operates at Layer 2 (Data Link Layer), it typically works only within a single broadcast domain, usually limited to a single router or network segment.
> [!NOTE]
> Ping and `ARPSCAN` use different protocols so even if you can ping devices it doesn't mean `ARPSCAN` can detect them.
To scan multiple locally accessible network segments, add them as subnets according to the [subnets](./SUBNETS.md) documentation. If `ARPSCAN` is not suitable for your setup, read on.
## Complex Use Cases
The following network setups might make some devices undetectable with `ARPSCAN`. Check the specific setup to understand the cause and find potential workarounds to report on these devices.
### Wi-Fi Extenders
Wi-Fi extenders typically create a separate network or subnet, which can prevent network scanning tools like `arp-scan` from detecting devices behind the extender.
> **Possible workaround**: Scan the specific subnet that the extender uses, if it is separate from the main network.
### VPNs
ARP operates at Layer 2 (Data Link Layer) and works only within a local area network (LAN). VPNs, which operate at Layer 3 (Network Layer), route traffic between networks, preventing ARP requests from discovering devices outside the local network.
VPNs use virtual interfaces (e.g., `tun0`, `tap0`) to encapsulate traffic, bypassing ARP-based discovery. Additionally, many VPNs use NAT, which masks individual devices behind a shared IP address.
> **Possible workaround**: Configure the VPN to bridge networks instead of routing to enable ARP, though this depends on the VPN setup and security requirements.
# Other Workarounds
The following workarounds should work for most complex network setups.
## Supplementing Plugins
You can use supplementary plugins that employ alternate methods. Protocols used by the `SNMPDSC` or `DHCPLSS` plugins are widely supported on different routers and can be effective as workarounds. Check the [plugins list](./PLUGINS.md) to find a plugin that works with your router and network setup.
## Multiple NetAlertX Instances
If you have servers in different networks, you can set up separate NetAlertX instances on those subnets and synchronize the results into one instance using the [`SYNC` plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/sync).
## Manual Entry
If you don't need to discover new devices and only need to report on their status (`online`, `offline`, `down`), you can manually enter devices and check their status using the [`ICMP` plugin](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/icmp_scan/), which uses the `ping` command internally.
For more information on how to add devices manually (or dummy devices), refer to the [Device Management](./DEVICE_MANAGEMENT.md) documentation.
To create truly dummy devices, you can use a loopback IP address (e.g., `0.0.0.0` or `127.0.0.1`) so they appear online.
## NMAP and Fake MAC Addresses
Scanning remote networks with NMAP is possible (via the `NMAPDEV` plugin), but since it cannot retrieve the MAC address, you need to enable the `NMAPDEV_FAKE_MAC` setting. This will generate a fake MAC address based on the IP address, allowing you to track devices. However, this can lead to inconsistencies, especially if the IP address changes or a previously logged device is rediscovered. If this setting is disabled, only the IP address will be discovered, and devices with missing MAC addresses will be skipped.
Check the [NMAPDEV plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/nmap_dev_scan) for details
## Setting up better name discovery with Reverse DNS
If you are running a DNS server, such as **AdGuard**, set up **Private reverse DNS servers** for a better name resolution on your network. Enabling this setting will enable NetAlertX to execute dig and nslookup commands to automatically resolve device names based on their IP addresses.
> Example 1: Reverse DNS `disabled`
>
> ```
> jokob@Synology-NAS:/$ nslookup 192.168.1.58
> ** server can't find 58.1.168.192.in-addr.arpa: NXDOMAIN
> ```
> Example 2: Reverse DNS `enabled`
>
> ```
> jokob@Synology-NAS:/$ nslookup 192.168.1.58
> 45.1.168.192.in-addr.arpa name = jokob-NUC.localdomain.
> ```
### Enabling reverse DNS in AdGuard
1. Navigate to **Settings** -> **DNS Settings**
2. Locate **Private reverse DNS servers**
3. Enter your router IP address, such as `192.168.1.1`
4. Make sure you have **Use private reverse DNS resolvers** ticked.
5. Click **Apply** to save your settings.
### Specifying the DNS in the container
You can specify the DNS server in the docker-compose to improve name resolution on your network.
```yaml
services:
netalertx:
container_name:netalertx
image:"ghcr.io/jokob-sk/netalertx:latest"
restart:unless-stopped
volumes:
- /home/netalertx/config:/app/config
- /home/netalertx/db:/app/db
- /home/netalertx/log:/app/log
environment:
- TZ=Europe/Berlin
- PORT=20211
network_mode:host
dns:# specifying the DNS servers used for the container
- 10.8.0.1
- 10.8.0.17
```
### Using a custom resolv.conf file
You can configure a custom **/etc/resolv.conf** file in **docker-compose.yml** and set the nameserver to your LAN DNS server (e.g.: Pi-Hole). See the relevant [resolv.conf man](https://www.man7.org/linux/man-pages/man5/resolv.conf.5.html) entry for details.
#### docker-compose.yml:
```yaml
version:"3"
services:
netalertx:
container_name:netalertx
image:"ghcr.io/jokob-sk/netalertx:latest"
restart:unless-stopped
volumes:
- ./config/app.conf:/app/config/app.conf
- ./db:/app/db
- ./log:/app/log
- ./config/resolv.conf:/etc/resolv.conf # Mapping the /resolv.conf file for better name resolution
environment:
- TZ=Europe/Berlin
- PORT=20211
ports:
- "20211:20211"
network_mode:host
```
#### ./config/resolv.conf:
The most important below is the `nameserver` entry (you can add multiple):
> Submitted by amazing [cvc90](https://github.com/cvc90) 🙏
> [!NOTE]
> There are 2 NGINX files for NetAlertX, one for the bare-metal Debian install (`netalertx.debian.conf`), and one for the docker container (`netalertx.template.conf`). Both can be found in the [install](https://github.com/jokob-sk/NetAlertX/tree/main/install) folder. Map, or use, the one appropriate for your setup.
## NGINX HTTP Configuration (Direct Path)
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
@@ -22,26 +26,26 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/
<br>
## NGINX HTTP Configuration (Sub Path)
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
location ^~ /pi.alert/ {
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
}
}
```
@@ -50,34 +54,34 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/
<br>
## NGINX HTTP Configuration (Sub Path) with module ngx_http_sub_module
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
2. In this file, paste the following code:
```
server {
listen 80;
server_name pi.alert;
server_name netalertx;
proxy_preserve_host on;
location ^~ /pi.alert/ {
location ^~ /netalertx/ {
proxy_pass http://localhost:20211/;
proxy_pass_reverse http://localhost:20211/;
proxy_redirect ~^/(.*)$ /pi.alert/$1;
rewrite ^/pi.alert/?(.*)$ /$1 break;
proxy_redirect ~^/(.*)$ /netalertx/$1;
rewrite ^/netalertx/?(.*)$ /$1 break;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/pi.alert/';
sub_filter '(?>$host)/css' '/pi.alert/css';
sub_filter '(?>$host)/js' '/pi.alert/js';
sub_filter '/img' '/pi.alert/img';
sub_filter '/lib' '/pi.alert/lib';
sub_filter '/php' '/pi.alert/php';
sub_filter 'href="/' 'href="/netalertx/';
sub_filter '(?>$host)/css' '/netalertx/css';
sub_filter '(?>$host)/js' '/netalertx/js';
sub_filter '/img' '/netalertx/img';
sub_filter '/lib' '/netalertx/lib';
sub_filter '/php' '/netalertx/php';
}
}
```
@@ -86,23 +90,23 @@
`nginx -s reload` or `systemctl restart nginx`
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
4. Once NGINX restarts, you should be able to access the proxy website at http://netalertx/netalertx/
<br>
**NGINX HTTPS Configuration (Direct Path)**
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
1. On your NGINX server, create a new file called /etc/nginx/sites-available/netalertx
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/449#discussioncomment-7281442))
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/449#discussioncomment-7281442))
Asuming the user already has a working Traefik setup, this is what's needed to make Pi.Alert work at a URL like www.domain.com/pialert/.
Asuming the user already has a working Traefik setup, this is what's needed to make NetAlertX work at a URL like www.domain.com/netalertx/.
Note: Everything in these configs assumes '**www.domain.com**' as your domainname and '**section31**' as an arbitrary name for your certificate setup. You will have to substitute these with your own.
Also, I use the prefix '**pialert**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
Also, I use the prefix '**netalertx**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
Content of my yaml-file (this is the generic Traefik config, which defines which ports to listen on, redirect http to https and sets up the certificate process).
It also contains Authelia, which I use for authentication.
This part contains nothing specific to Pi.Alert.
This part contains nothing specific to NetAlertX.
```yaml
version: '3.8'
@@ -402,29 +406,29 @@ services:
restart: u
nless-stopped
```
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for Pi.Alert:
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for NetAlertX:
The following are self-defined keywords, everything else is traefik keywords:
To make Pi.Alert work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
To make NetAlertX work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
NetAlertX is an execution framework. In order to run scanners and plugins, the application has to have access to privileged system resources. It is not recommended to expose NetAlertX to the internet without taking basic security precautions. It is highly recommended to use a VPN to access the application and to set up a password for the web interface before exposing the UI online.
## VPN
VPNs allow you to securely access your NetAlertX instance from remote locations without exposing it to the internet. A VPN encrypts your connection and prevents unauthorized access.
### Tailscale as an Alternative
If setting up a traditional VPN is not ideal, you can use [Tailscale](https://tailscale.com/) as an easy alternative. Tailscale creates a secure, encrypted connection between your devices without complex configuration. Since NetAlertX is designed to be run on private networks, Tailscale can provide a simple way to securely connect to your instance from anywhere.
## Setting a Password
By default, NetAlertX does not enforce authentication, but it is highly recommended to set a password before exposing the web interface.
Configure `SETPWD_enable_password` to `true` and enter your password in `SETPWD_password`. When enabled, a login dialog is displayed. If facing issues, you can always disable the login by setting `SETPWD_enable_password=false` in your `app.conf` file.
- The default password is `123456`.
- Passwords are stored as SHA256 hashes for security.
## Additional Security Measures
- **Firewall Rules**: Ensure that only trusted IPs can access the NetAlertX instance.
- **Limit Plugin Permissions**: Only enable the plugins necessary for your setup.
- **Keep Software Updated**: Regularly update NetAlertX to receive the latest security patches.
- **Use Read-Only API Keys**: If exposing APIs, limit privileges with read-only keys where applicable.
By following these security recommendations, you can help protect your NetAlertX instance from unauthorized access and potential misuse.
- **Description:** Displays the first detected connection time for the device.
- **Editability:** Uneditable (auto-detected).
- **Source:** Automatically captured when the device is first added to the system.
2.**Date and Time of Last Connection**
- **Description:** Shows the most recent time the device was online.
- **Editability:** Uneditable (auto-detected).
- **Source:** Updated with every new connection event.
3.**Offline Devices with Missing or Conflicting Data**
- **Description:** Handles cases where a device is offline but has incomplete or conflicting session data (e.g., missing start times).
- **Handling:** The system flags these cases for review and attempts to infer missing details.
---
## How Sessions are Discovered and Calculated
### 1. Detecting New Devices
When a device is first detected in the network, the system logs it in the events table:
`INSERT INTO Events (eve_MAC, eve_IP, eve_DateTime, eve_EventType, eve_AdditionalInfo, eve_PendingAlertEmail) SELECT cur_MAC, cur_IP, '{startTime}', 'New Device', cur_Vendor, 1 FROM CurrentScan WHERE NOT EXISTS (SELECT 1 FROM Devices WHERE devMac = cur_MAC)`
- Devices scanned in the current cycle (**CurrentScan**) are checked against the **Devices** table.
- If a device is new:
- A **New Device** event is logged.
- The device’s MAC, IP, vendor, and detection time are recorded.
### 2. Logging Connection Sessions
When a new connection is detected, the system creates a session record:
`INSERT INTO Sessions (ses_MAC, ses_IP, ses_EventTypeConnection, ses_DateTimeConnection, ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_StillConnected, ses_AdditionalInfo) SELECT cur_MAC, cur_IP, 'Connected', '{startTime}', NULL, NULL, 1, cur_Vendor FROM CurrentScan WHERE NOT EXISTS (SELECT 1 FROM Sessions WHERE ses_MAC = cur_MAC)`
- A new session is logged in the **Sessions** table if no prior session exists.
- Fields like `MAC`, `IP`, `Connection Type`, and `Connection Time` are populated.
- The `Still Connected` flag is set to `1` (active connection).
### 3. Handling Missing or Conflicting Data
- Devices with incomplete or conflicting session data (e.g., missing start times) are detected.
- The system flags these records and attempts corrections by inferring details from available data.
### 4. Updating Sessions
- When a device reconnects, its session is updated with a new connection timestamp.
- When a device disconnects:
- The **Disconnection Time** is recorded.
- The `Still Connected` flag is set to `0`.
The session information is then used to display the device presence under **Monitoring** -> **Presence**.
This is an explanation how settings are handled intended for anyone thinking about writing their own plugin or contributing to the project.
If you are a user of the app, settings should be described in the `Settings` section of the app. Open an issue if you'd like to clarify any of the settings.
If you are a user of the app, settings have a detailed description in the _Settings_ section of the app. Open an issue if you'd like to clarify any of the settings.
### 🛢 Data storage
The source of truth for user-defined values is the `pialert.conf` file. Editing the file makes the App overwrite values in the `Settings` database table and in the `table_settings.json` file.
The source of truth for user-defined values is the `app.conf` file. Editing the file makes the App overwrite values in the `Settings` database table and in the `table_settings.json` file.
#### Settings database table
The `Settings` database table contains settings for App run purposes. The table is recreated every time the App restarts. The settings are loaded from the source-of-truth, that is the `pialert.conf` file. A high-level overview on the database structure can be found in the [database documentation](/docs/DATABASE.md).
The `Settings` database table contains settings for App run purposes. The table is recreated every time the App restarts. The settings are loaded from the source-of-truth, that is the `app.conf` file. A high-level overview on the database structure can be found in the [database documentation](./DATABASE.md).
#### table_settings.json
This is the [API endpoint](/docs/API.md) that reflects the state of the `Settings` database table. Settings can be accessed with the:
This is the [API endpoint](./API.md) that reflects the state of the `Settings` database table. Settings can be accessed with the:
*`getSetting(key)` JavaScript method
The json file is also cached on the client-side local storage of the browser.
#### pialert.conf
#### app.conf
> [!NOTE]
> This is the source of truth for settings. User-defined values in this files always override default values specified in the Plugin definition.
The App generates two `pialert.conf` entries for every setting (Since version 23.8+). One entry is the setting value, the second is the `__metadata` associated with the setting. This `__metadata` entry contains the full setting definition in JSON format. This should helps the future extensibility of the Settings system.
The App generates two `app.conf` entries for every setting (Since version 23.8+). One entry is the setting value, the second is the `__metadata` associated with the setting. This `__metadata` entry contains the full setting definition in JSON format. Currently unused, but intended to be used in future to extend the Settings system.
#### Plugin settings
> [!NOTE]
> This is the preferred way adding settings going forward. I'll be likely migrating all app settings into plugin-based settings.
Plugin settings are loaded dynamically from the `config.json` of individual plugins. If a setting isn't defined in the `pialert.conf` file, it is initialized via the `default_value` property of a setting from the `config.json` file. Check the [Plugins documentation](/front/plugins/README.md), section `⚙ Setting object structure` for details on the structure of the setting.
Plugin settings are loaded dynamically from the `config.json` of individual plugins. If a setting isn't defined in the `app.conf` file, it is initialized via the `default_value` property of a setting from the `config.json` file. Check the [Plugins documentation](https://github.com/jokob-sk/NetAlertX/blob/main/docs/PLUGINS.md#-setting-object-structure), section `⚙ Setting object structure` for details on the structure of the setting.
![Screen 1][screen1]
### Settings Process flow
The process flow is mostly managed by the [initialise.py](/pialert/initialise.py) file.
The process flow is mostly managed by the [initialise.py](/server/initialise.py) file.
The script is responsible for reading user-defined values from a configuration file (`pialert.conf`), initializing settings, and importing them into a database. It also handles plugins and their configurations.
The script is responsible for reading user-defined values from a configuration file (`app.conf`), initializing settings, and importing them into a database. It also handles plugins and their configurations.
Here's a high-level description of the code:
@@ -49,7 +49,7 @@ Here's a high-level description of the code:
-`importConfigs`: This function is the main entry point of the script. It imports user settings from a configuration file, processes them, and saves them to the database.
-`read_config_file`: This function reads the configuration file (`pialert.conf`) and returns a dictionary containing the key-value pairs from the file.
-`read_config_file`: This function reads the configuration file (`app.conf`) and returns a dictionary containing the key-value pairs from the file.
2. Importing Configuration and Initializing Settings:
- The `importConfigs` function starts by checking the modification time of the configuration file to determine if it needs to be re-imported. If the file has not been modified since the last import, the function skips the import process.
@@ -74,4 +74,4 @@ Here's a high-level description of the code:
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANS (see exceptions below).
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANs (see VLAN exceptions below).
## Examples
`ARPSCAN` can scan multiple networks if the network allows it. To scan networks directly, the subnets must be accessible from the network where NetAlertX is running. This means NetAlertX needs to have access to the interface attached to that subnet.
* Examples for one and two subnets (❗ Note the `['...', '...']` format):
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0', '192.168.1.0/24 --interface=eth1 -vlan=107']`
> [!WARNING]
> If you don't see all expected devices run the following command in the NetAlertX container (replace the interface and ip mask):
> `sudo arp-scan --interface=eth0192.168.1.0/24`
>
> If this command returns no results, the network is not accessible due to your network or firewall restrictions (Wi-Fi Extenders, VPNs and inaccessible networks). If direct scans are not possible, check the [remote networks documentation](./REMOTE_NETWORKS.md) for workarounds.
## Example Values
> [!NOTE]
> Please use the UI to configure settings as it ensures the config file is in the correct format. Edit `app.conf` directly only when really necessary.
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 --vlan=107']`
> [!TIP]
> When adding more subnets, you may need to increase both the scan interval (`ARPSCAN_RUN_SCHD`) and the timeout (`ARPSCAN_RUN_TIMEOUT`)—as well as similar settings for related plugins.
>
> If the timeout is too short, you may see timeout errors in the log. To prevent the application from hanging due to unresponsive plugins, scans are canceled when they exceed the timeout limit.
>
> To fix this:
> - Reduce the subnet size (e.g., change `/16` to `/24`).
> - Increase the timeout (e.g., set `ARPSCAN_RUN_TIMEOUT` to `300` for a 5-minute timeout).
> - Extend the scan interval (e.g., set `ARPSCAN_RUN_SCHD` to `*/10 * * * *` to scan every 10 minutes).
>
> For more troubleshooting tips, see [Debugging Plugins](./DEBUG_PLUGINS.md).
---
## Explanation
### Network mask
### Network Mask
**Example value:`192.168.1.0/24`**
**Example value:** `192.168.1.0/24`
The arp-scan time itself depends on the number of IP addresses to check.
The `arp-scan` time itself depends on the number of IP addresses to check.
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set on the `SCAN_SUBNETS` setting.
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536. Every IP takes a couple of seconds. This means that with an incorrect configuration, the arp-scan will take hours to complete instead of seconds.
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set in the `SCAN_SUBNETS` setting.
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536 IPs. Each IP takes a couple of seconds, so an incorrect configuration could make `arp-scan` take hours instead of seconds.
Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges 192.168.1.0 to 192.168.1.255.
Specify the network filter, which **significantly** speeds up the scan process. For example, the filter `192.168.1.0/24` covers IP ranges from `192.168.1.0` to `192.168.1.255`.
### Network interface (adapter)
### Network Interface (Adapter)
**Example value:`--interface=eth0`**
**Example value:** `--interface=eth0`
The adapter will probably be `eth0` or `eth1`. (Check `System info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s))
The adapter will probably be `eth0` or `eth1`. (Check `System Info` > `Network Hardware`, or run `iwconfig` in the container to find your interface name(s)).
> Run `iwconfig` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
> As an alternative to `iwconfig`, run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`):
> ```bash
> Synology-NAS:/# ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'
> sit0@NONE
> eth1
> eth0
> ```
### VLANs
**Example value: `-vlan=107`**
**Example value:**`--vlan=107`
- Append e.g.:`-vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple vlans. More details in this [comment in this issue](https://github.com/jokob-sk/Pi.Alert/issues/170#issuecomment-1419902988)
- Append `--vlan=107` to the `SCAN_SUBNETS` field (e.g.: `192.168.1.0/24 --interface=vmbr0 --vlan=107`) for multiple VLANs.
#### VLANs on a Hyper-V Setup
> Community-sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/404).
**Tested Setup:** Bare Metal → Hyper-V on Win Server 2019 → Ubuntu 22.04 VM → Docker → NetAlertX.
**Approach 1 (may cause issues):**
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. This might interfere with other applications such as Authentik.
**Approach 2 (working example):**
Network connections to switches are configured as trunk and allow all VLANs access to the server.
By default, Hyper-V only allows untagged packets through to the VM interface, blocking VLAN-tagged packets. To fix this, follow these steps:
1. Run the following command in PowerShell on the Hyper-V machine:
```powershell
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
```
#### VLANs on a Hyper-V setup
2. Within the VM, set up sub-interfaces for each VLAN to enable scanning. On Ubuntu 22.04, Netplan can be used. In /etc/netplan/00-installer-config.yaml, add VLAN definitions:
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/404).
```yaml
network:
ethernets:
eth0:
dhcp4: yes
vlans:
eth0.2:
id: 2
link: eth0
addresses: [ "192.168.2.2/24" ]
routes:
- to: 192.168.2.0/24
via: 192.168.1.1
```
> [!NOTE]
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> PiAlert.
3. Run `sudo netplan apply` to activate the interfaces for scanning in NetAlertX.
**Approach 1 (may cause issues):**
In this case, use `192.168.2.0/24 --interface=eth0.2` in NetAlertX.
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. The issue may stem from the creation of routes for network time servers or domain controllers on every interface, thereby preventing proper synchronization of the underlying Ubuntu VM. This interference can affect the performance of other applications such as Authentik.
#### VLAN Support & Exceptions
**Approach 2 (working example)**
Please note the accessibility of macvlans when configured on the same computer. This is a general networking behavior, but feel free to clarify via a PR/issue.
Network connections to switches are configured as trunk and allow all VLANs access to the server.
By default Hyper-V only allows untagged packets through to the VM interface and no VLAN tagged packets get through. In order to fix this follow these steps:
1) Run the following command in Powershell on the Hyper-V machine:
```shell
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
```
(There might be other ways how adjust this.)
2) Within the VM, set up sub-interfaces for each of the VLANs so they can be scanned. On Ubuntu 22.04 Netplan can be used.
In /etc/netplan/00-installer-config.yaml, add vlan definitions:
```
network:
ethernets:
eth0:
dhcp4: yes
vlans:
eth0.2:
id: 2
link: eth0
addresses: [ "192.168.2.2/24" ]
routes:
- to: 192.168.2.0/24
via: 192.168.1.1
```
3) Run `sudo netplan apply` and the interfaces are then available to scan in PiAlert.
4) In this case, use `192.168.2.0/24 --interface=eth0.2` in PiAlert
Please note the accessibility of the macvlans when they are configured on the same computer. My understanding this is a general networking behavior, but feel free to clarify via a PR/issue.
- Pi.Alert does not detect the macvlan container when it is running on the same computer.
- Pi.Alert recognizes the macvlan container when it is running on a different computer.
- NetAlertX does not detect the macvlan container when it is running on the same computer.
- NetAlertX recognizes the macvlan container when it is running on a different computer.
There are different ways to install NetAlertX on a Synology, including SSH-ing into the machine and using the command line. For this guide, we will use the Project option in Container manager.
## Create the folder structure
The folders you are creating below will contain the configuration and the database. Back them up regularly.
This guide outlines approaches for updating Docker containers, usually when upgrading to a newer version of NetAlertX. Each method offers different benefits depending on the situation. Here are the methods:
- Manual: Direct commands to stop, remove, and rebuild containers.
- Dockcheck: Semi-automated with more control, suited for bulk updates.
- Watchtower: Fully automated, runs continuously to check and update containers.
You can choose any approach that fits your workflow.
> In the examples I assume that the container name is `netalertx` and the image name is `netalertx` as well.
> [!NOTE]
> See also [Backup strategies](./BACKUPS.md) to be on the safe side.
## 1. Manual Updates
Use this method when you need precise control over a single container or when dealing with a broken container that needs immediate attention.
Example Commands
To manually update the `netalertx` container, stop it, delete it, remove the old image, and start a fresh one with `docker-compose`.
```bash
# Stop the container
sudo docker container stop netalertx
# Remove the container
sudo docker container rm netalertx
# Remove the old image
sudo docker image rm netalertx
# Pull and start a new container
sudo docker-compose up -d
```
### Alternative: Force Pull with Docker Compose
You can also use `--pull always` to ensure Docker pulls the latest image before starting the container:
```bash
sudo docker-compose up --pull always -d
```
## 2. Dockcheck for Bulk Container Updates
Always check the [Dockcheck](https://github.com/mag37/dockcheck) docs if encountering issues with the guide below.
Dockcheck is a useful tool if you have multiple containers to update and some flexibility for handling potential issues that might arise during mass updates. Dockcheck allows you to inspect each container and decide when to update.
### Example Workflow with Dockcheck
You might use Dockcheck to:
- Inspect container versions.
- Pull the latest images in bulk.
- Apply updates selectively.
Dockcheck can help streamline bulk updates, especially if you’re managing multiple containers.
Below is a script I use to run an update of the Dockcheck script and start a check for new containers:
Always check the [watchtower](https://github.com/containrrr/watchtower) docs if encountering issues with the guide below.
Watchtower monitors your Docker containers and automatically updates them when new images are available. This is ideal for ongoing updates without manual intervention.
### Setting Up Watchtower
#### 1. Pull the Watchtower Image:
```bash
docker pull containrrr/watchtower
```
#### 2. Run Watchtower to update all images:
```bash
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--interval 300# Check for updates every 5 minutes
```
#### 3. Run Watchtower to update only NetAlertX:
You can specify which containers to monitor by listing them. For example, to monitor netalertx only:
```bash
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower netalertx
```
## Summary
- Manual: Ideal for individual or critical updates.
- Dockcheck: Suitable for controlled, mass updates.
- Watchtower: Fully automated, best for continuous deployment setups.
These approaches allow you to maintain flexibility in how you update Docker containers, depending on the urgency and scale of the update.
Since version 23.01.14 PiAlert uses a simple timestamp-based version check to verify if a new version is available. You can check the [current and past releases here](https://github.com/jokob-sk/Pi.Alert/releases), or have a look at what I'm [currently working on](https://github.com/jokob-sk/Pi.Alert/issues/138).
Since version 23.01.14 NetAlertX uses a simple timestamp-based version check to verify if a new version is available. You can check the [current and past releases here](https://github.com/jokob-sk/NetAlertX/releases), or have a look at what I'm [currently working on](https://github.com/jokob-sk/NetAlertX/issues/138).
If you are not on the latest version, the app will notify you, that a new released version is avialable the following way:
@@ -8,18 +8,18 @@ If you are not on the latest version, the app will notify you, that a new releas
If any notification occurs and an email is sent, the email will contain a note that a new version is available. See the sample email below:


### 🆕 In the UI
In the UI via a notification Icon and via a custom message in the Maintenance section.


For a comparison, this is how the UI looks like if you are on the latest stable image:


## Implementation details
During build a [/home/pi/pialert/front/buildtimestamp.txt](https://github.com/jokob-sk/Pi.Alert/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion():` method in `pialert.py` for details).
During build a [/app/front/buildtimestamp.txt](https://github.com/jokob-sk/NetAlertX/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion():` method for details).
N8N can be used for more advanced conditional notification use cases. For example, you want only to get notified if two out of a specified list of devices is down. Or you can use other plugins to process the notifiations further. The below is a simple example of sending an email on a webhook.
See [sample JSON](https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json) if you want to see the JSON paths used in the email template below
See [sample JSON](https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json) if you want to see the JSON paths used in the email template below
Pi.Alert will use the configured secret to create a hash signature of the request body. This SHA256-HMAC signature will appear in the `X-Webhook-Signature` header of each request to the webhook target URL. You can use the value of this header to validate the request was sent by Pi.Alert.
NetAlertX will use the configured secret to create a hash signature of the request body. This SHA256-HMAC signature will appear in the `X-Webhook-Signature` header of each request to the webhook target URL. You can use the value of this header to validate the request was sent by NetAlertX.
## Activating webhook signatures
@@ -12,7 +12,7 @@ All you need to do in order to add a signature to the request headers is to set
There are a few things to keep in mind when validating the webhook delivery:
-Pi.Alert uses an HMAC hex digest to compute the hash
-NetAlertX uses an HMAC hex digest to compute the hash
- The signature in the `X-Webhook-Signature` header always starts with `sha256=`
- The hash signature is generated using the configured `WEBHOOK_SECRET` and the request body.
- Never use a plain `==` operator. Instead, consider using a method like [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) or [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b), which performs a "constant time" string comparison to help mitigate certain timing attacks against regular equality operators, or regular loops in JIT-optimized languages.
Check for browser console (F12 browser dev console) errors + check different browsers.
### 3. Clear the app cache and cached JavaScript files
Refresh the browser cache (usually shoft + refresh), try a private window, or different browsers. Please also refresh the app cache by clicking the 🔃 (reload) button in the header of the application.
### 4. Disable proxies
If you have any reverse proxy or similar, try disabling it.
### 5. Disable your firewall
If you are using a firewall, try to temporarily disabling it.
### 6. Post your docker start details
If you haven't, post your docker compose/run command.
### 7. Check for errors in your PHP/NGINX error logs
In the container execute and investigate:
`cat /var/log/nginx/error.log`
`cat /app/log/app.php_errors.log`
### 8. Make sure permissions are correct
> [!TIP]
> You can try to start the container without mapping the `/app/config` and `/app/db` dirs and if the UI shows up then the issue is most likely related to your file system permissions or file ownership.
Please read the [Permissions troubleshooting guide](./FILE_PERMISSIONS.md) and provide a screesnhot of the permissions and ownership in the `/app/db` and `app/config` directories.
The workflows module in 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.
Below are a few examples that demonstrate how this module can be used to simplify network management tasks.
## Updating Workflows
> [!NOTE]
> In order to apply a workflow change, you must first **Save** the changes and then reload the application by clicking **Restart server**.
## Workflow components
### 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.
> [!TIP]
> Workflows not running? Check the [Workflows debugging](./WORKFLOWS_DEBUGGING.md) guide how to troubleshoot triggers and conditions.
#### Example Trigger:
- **Object Type**: `Devices`
- **Event Type**: `update`
This trigger will activate when a `Device` object is updated.
Conditions determine whether a workflow should proceed based on certain criteria. These criteria can be set for specific fields, such as whether a device is from a certain vendor, or whether it is new or archived. You can combine conditions using logical operators (`AND`, `OR`).
> [!TIP]
> To better understand how to use specific Device fields, please read through the [Database overview](./DATABASE.md) guide.
#### Example Condition:
- **Logic**: `AND`
- **Field**: `devVendor`
- **Operator**: `contains` (case in-sensitive)
- **Value**: `Google`
This condition checks if the device's vendor is `Google`. The workflow will only proceed if the condition is true.
### Actions

Actions define the tasks that the workflow will perform once the conditions are met. Actions can include updating fields or deleting devices.
You can include multiple actions that should execute once the conditions are met.
#### Example Action:
- **Action Type**: `update_field`
- **Field**: `devIsNew`
- **Value**: `0`
This action updates the `devIsNew` field to `0`, marking the device as no longer new.
# Examples
Below you can find a couple of configuration examples.
> 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`).
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.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.