diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 2cd20c62..61f29310 100755
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,3 @@
github: jokob-sk
-patreon: 84385063
+patreon: netalertx
buy_me_a_coffee: jokobsk
diff --git a/Dockerfile b/Dockerfile
index a19ef51e..913b64e4 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,7 +13,7 @@ ENV PATH="/opt/venv/bin:$PATH"
COPY . ${INSTALL_DIR}/
-RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git \
+RUN pip install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag git+https://github.com/foreign-sub/aiofreepybox.git \
&& bash -c "find ${INSTALL_DIR} -type d -exec chmod 750 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f -exec chmod 640 {} \;" \
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
diff --git a/Dockerfile.debian b/Dockerfile.debian
index b3cf222f..e43eb1c2 100755
--- a/Dockerfile.debian
+++ b/Dockerfile.debian
@@ -43,7 +43,7 @@ RUN phpenmod -v 8.2 sqlite3
RUN apt-get install -y python3-venv
RUN python3 -m venv myenv
-RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag "
+RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install openwrt-luci-rpc asusrouter asyncio aiohttp graphene flask flask-cors unifi-sm-api tplink-omada-client wakeonlan pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros yattag "
# Create a buildtimestamp.txt to later check if a new version was released
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt
diff --git a/docs/DEBUG_PHP.md b/docs/DEBUG_PHP.md
new file mode 100755
index 00000000..ab32d5a0
--- /dev/null
+++ b/docs/DEBUG_PHP.md
@@ -0,0 +1,34 @@
+# Debugging backend PHP issues
+
+## Logs in UI
+
+
+
+You can view recent backend PHP errors directly in the **Maintenance > Logs** section of the UI. This provides quick access to logs without needing terminal access.
+
+## Accessing logs directly
+
+Sometimes, the UI might not be accessible. In that case, you can access the logs directly inside the container.
+
+### Step-by-step:
+
+1. **Open a shell into the container:**
+
+ ```bash
+ docker exec -it netalertx /bin/sh
+ ```
+
+2. **Check the NGINX error log:**
+
+ ```bash
+ cat /var/log/nginx/error.log
+ ```
+
+3. **Check the PHP application error log:**
+
+ ```bash
+ cat /app/log/app.php_errors.log
+ ```
+
+These logs will help identify syntax issues, fatal errors, or startup problems when the UI fails to load properly.
+
diff --git a/docs/img/DEBUG/maintenance_debug_php.png b/docs/img/DEBUG/maintenance_debug_php.png
new file mode 100755
index 00000000..3b59d56a
Binary files /dev/null and b/docs/img/DEBUG/maintenance_debug_php.png differ
diff --git a/docs/img/DEVICE_MANAGEMENT/Devices_CreateDummyDevice.png b/docs/img/DEVICE_MANAGEMENT/Devices_CreateDummyDevice.png
index 009a6770..316e79c8 100755
Binary files a/docs/img/DEVICE_MANAGEMENT/Devices_CreateDummyDevice.png and b/docs/img/DEVICE_MANAGEMENT/Devices_CreateDummyDevice.png differ
diff --git a/front/plugins/unifi_api_import/README.md b/front/plugins/unifi_api_import/README.md
new file mode 100755
index 00000000..900fae41
--- /dev/null
+++ b/front/plugins/unifi_api_import/README.md
@@ -0,0 +1,26 @@
+## Overview
+
+Unifi import plugin using the Site Manager API.
+
+> [!TIP]
+> The Site Manager API doesn't seems to have feature parity with the old API yet, so certain limitations apply.
+
+### Quick setup guide
+
+Navigate to your UniFi Site Manager _⚙️ Settings -> Control Plane -> Integrations_.
+
+- `api_key` : You can generate your API key under the _Your API Keys_ section.
+- `base_url` : You can find your base url in the _API Request Format_ section, e.g. `https://192.168.100.1/proxy/network/integration/`
+- `version` : You can find your version as part of the url in the _API Request Format_ section, e.g. `v1`
+- `skip_ssl` : To skip SSL with you don't have an SSL certificate
+
+
+### Usage
+
+- Head to **Settings** > **Plugin name** to adjust the default values.
+
+### Notes
+
+- Version: 1.0.0
+- Author: `jokob-sk`
+- Release Date: `Aug 2025`
\ No newline at end of file
diff --git a/front/plugins/unifi_api_import/config.json b/front/plugins/unifi_api_import/config.json
new file mode 100755
index 00000000..e9dac882
--- /dev/null
+++ b/front/plugins/unifi_api_import/config.json
@@ -0,0 +1,585 @@
+{
+ "code_name": "unifi_api_import",
+ "unique_prefix": "UNIFIAPI",
+ "plugin_type": "device_scanner",
+ "execution_order" : "Layer_0",
+ "enabled": true,
+ "data_source": "script",
+ "mapped_to_table": "CurrentScan",
+ "data_filters": [
+ {
+ "compare_column": "Object_PrimaryID",
+ "compare_operator": "==",
+ "compare_field_id": "txtMacFilter",
+ "compare_js_template": "'{value}'.toString()",
+ "compare_use_quotes": true
+ }
+ ],
+ "show_ui": true,
+ "localized": ["display_name", "description", "icon"],
+ "display_name": [
+ {
+ "language_code": "en_us",
+ "string": "Display Name"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Plugin to ..."
+ }
+ ],
+ "icon": [
+ {
+ "language_code": "en_us",
+ "string": ""
+ }
+ ],
+ "params": [],
+ "settings": [
+ {
+ "function": "RUN",
+ "events": ["run"],
+ "type": {
+ "dataType": "string",
+ "elements": [
+ { "elementType": "select", "elementOptions": [], "transformers": [] }
+ ]
+ },
+
+ "default_value": "disabled",
+ "options": [
+ "disabled",
+ "once",
+ "schedule"
+ ],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "When to run"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "When the plugin should run. Good options are always_after_scan, on_new_device, on_notification"
+ }
+ ]
+ },
+ {
+ "function": "RUN_SCHD",
+ "type": {
+ "dataType": "string",
+ "elements": [
+ {
+ "elementType": "span",
+ "elementOptions": [
+ {
+ "cssClasses": "input-group-addon validityCheck"
+ },
+ {
+ "getStringKey": "Gen_ValidIcon"
+ }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "input",
+ "elementOptions": [
+ {
+ "onChange": "validateRegex(this)"
+ },
+ {
+ "base64Regex": "Xig/OlwqfCg/OlswLTldfFsxLTVdWzAtOV18WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlswLTldfDFbMC05XXwyWzAtM118WzAtOV0rLVswLTldK3xcKi9bMC05XSspKVxzKyg/OlwqfCg/OlsxLTldfFsxMl1bMC05XXwzWzAxXXxbMC05XSstWzAtOV0rfFwqL1swLTldKykpXHMrKD86XCp8KD86WzEtOV18MVswLTJdfFswLTldKy1bMC05XSt8XCovWzAtOV0rKSlccysoPzpcKnwoPzpbMC02XXxbMC02XS1bMC02XXxcKi9bMC05XSspKSQ="
+ }
+ ],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": "*/5 * * * *",
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Schedule"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Only enabled if you select schedule in the SYNC_RUN setting. Make sure you enter the schedule in the correct cron-like format (e.g. validate at crontab.guru). For example entering 0 4 * * * will run the scan after 4 am in the TIMEZONE you set above. Will be run NEXT time the time passes."
+ }
+ ]
+ },
+ {
+ "function": "CMD",
+ "type": {
+ "dataType": "string",
+ "elements": [
+ {
+ "elementType": "input",
+ "elementOptions": [{ "readonly": "true" }],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": "python3 /app/front/plugins/unifi_api_import/unifi_api_import.py",
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Command"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Command to run. This can not be changed"
+ }
+ ]
+ },
+ {
+ "function": "RUN_TIMEOUT",
+ "type": {
+ "dataType": "integer",
+ "elements": [
+ {
+ "elementType": "input",
+ "elementOptions": [{ "type": "number" }],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": 10,
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Run timeout"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
+ }
+ ]
+ },
+ {
+ "function": "devCustomProps",
+ "type": {
+ "dataType": "array",
+ "elements": [
+ {
+ "elementType": "popupform",
+ "elementHasInputValue": 1,
+ "elementOptions": [
+ {
+ "fields": [
+ {
+ "function": "hide.site.name",
+ "type": {
+ "dataType": "string",
+ "elements": [
+ {
+ "elementType": "input",
+ "elementOptions": [
+ { "placeholder": "Enter value" },
+ { "suffix": "_in" },
+ { "cssClasses": "col-sm-10" },
+ { "prefillValue": "null" }
+ ],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": "default",
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Site name"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "The name of your site. Not used in code and only for.... "
+ }
+ ]
+
+ },
+ {
+ "settingKey": "hide.site.name",
+ "typeOverride": {
+ "dataType": "string",
+ "elements": [
+ {
+ "elementType": "span",
+ "elementOptions": [
+ {
+ "cssClasses": "input-group-addon iconPreview"
+ },
+ {
+ "getStringKey": "Gen_SelectIcon"
+ },
+ {
+ "customId": "CUSTPROP_icon_preview"
+ }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "select",
+ "elementHasInputValue": 1,
+ "elementOptions": [
+ {
+ "cssClasses": "iconInputVal myhidden"
+ },
+ {
+ "onChange": "updateIconPreview(this)"
+ },
+ {
+ "customParams": "CUSTPROP_icon,CUSTPROP_icon_preview"
+ }
+ ],
+ "transformers": []
+ }
+ ]
+ }
+ },
+ {
+ "settingKey": "hide.site.base_url",
+ "optionsOverride": "setting.CUSTPROP_type",
+ "typeOverride": {
+ "dataType": "string",
+ "elements": [
+ {
+ "elementType": "select",
+ "elementOptions": [],
+ "transformers": []
+ }
+ ]
+ }
+ },
+ {
+ "settingKey": "hide.site.version"
+ },
+ {
+ "settingKey": "hide.site.api_key"
+ },
+ {
+ "settingKey": "hide.site.verify_ssl"
+ }
+ ]
+ }
+ ],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": [],
+ "options": [],
+ "localized": [
+ "name",
+ "description"
+ ],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Sites"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Unifi sites"
+ }
+ ]
+ },
+ {
+ "function": "sites",
+ "type": {
+ "dataType": "array",
+ "elements": [
+ {
+ "elementType": "input",
+ "elementOptions": [
+ { "placeholder": "Enter value" },
+ { "suffix": "_in" },
+ { "cssClasses": "col-sm-10" },
+ { "prefillValue": "null" }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "button",
+ "elementOptions": [
+ { "sourceSuffixes": ["_in"] },
+ { "separator": "" },
+ { "cssClasses": "col-xs-12" },
+ { "onClick": "addList(this,false)" },
+ { "getStringKey": "Gen_Add" }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "select",
+ "elementHasInputValue": 1,
+ "elementOptions": [
+ { "multiple": "true" },
+ { "readonly": "true" },
+ { "editable": "true" }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "button",
+ "elementOptions": [
+ { "sourceSuffixes": [] },
+ { "separator": "" },
+ { "cssClasses": "col-xs-6" },
+ { "onClick": "removeAllOptions(this)" },
+ { "getStringKey": "Gen_Remove_All" }
+ ],
+ "transformers": []
+ },
+ {
+ "elementType": "button",
+ "elementOptions": [
+ { "sourceSuffixes": [] },
+ { "separator": "" },
+ { "cssClasses": "col-xs-6" },
+ { "onClick": "removeFromList(this)" },
+ { "getStringKey": "Gen_Remove_Last" }
+ ],
+ "transformers": []
+ }
+ ]
+ },
+ "maxLength": 50,
+ "default_value": [
+ "none",
+ "data",
+ "link",
+ "link_new_tab",
+ "show_notes",
+ "delete_dev",
+ "run_plugin"
+ ],
+ "options": [],
+ "localized": ["name","description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Type"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "List of property types. The default ones have specific functionality associated with it."
+ }
+ ]
+ }
+ ],
+ "database_column_definitions": [
+ {
+ "column": "Index",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "none",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Index"
+ }
+ ]
+ },
+ {
+ "column": "Object_PrimaryID",
+ "mapped_to_column": "cur_MAC",
+ "css_classes": "col-sm-3",
+ "show": true,
+ "type": "device_name_mac",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "MAC (name)"
+ }
+ ]
+ },
+ {
+ "column": "Object_SecondaryID",
+ "mapped_to_column": "cur_IP",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "device_ip",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "IP"
+ }
+ ]
+ },
+ {
+ "column": "Watched_Value1",
+ "mapped_to_column": "cur_Name",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Name"
+ }
+ ]
+ },
+ {
+ "column": "Watched_Value2",
+ "mapped_to_column": "cur_Vendor",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Vendor"
+ }
+ ]
+ },
+ {
+ "column": "Watched_Value3",
+ "mapped_to_column": "cur_Type",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Device Type"
+ }
+ ]
+ },
+ {
+ "column": "Watched_Value4",
+ "css_classes": "col-sm-2",
+ "show": false,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "N/A"
+ }
+ ]
+ },
+ {
+ "column": "Dummy",
+ "mapped_to_column": "cur_ScanMethod",
+ "mapped_to_column_data": {
+ "value": "Example Plugin"
+ },
+ "css_classes": "col-sm-2",
+ "show": false,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Scan method"
+ }
+ ]
+ },
+ {
+ "column": "DateTimeCreated",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Created"
+ }
+ ]
+ },
+ {
+ "column": "DateTimeChanged",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value": "",
+ "options": [],
+ "localized": ["name"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Changed"
+ }
+ ]
+ },
+ {
+ "column": "Status",
+ "css_classes": "col-sm-1",
+ "show": true,
+ "type": "replace",
+ "default_value": "",
+ "options": [
+ {
+ "equals": "watched-not-changed",
+ "replacement": "