diff --git a/.gitignore b/.gitignore
index ea9c9e15..f908738e 100755
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,7 @@ front/log/*
front/plugins/**/*.log
**/%40eaDir/
**/@eaDir/
+
+__pycache__/
+*.py[cod]
+*$py.class
\ No newline at end of file
diff --git a/db/pialert.db b/db/pialert.db
deleted file mode 100755
index ff4e2731..00000000
Binary files a/db/pialert.db and /dev/null differ
diff --git a/front/plugins/undiscoverables/README.md b/front/plugins/undiscoverables/README.md
new file mode 100644
index 00000000..622c5306
--- /dev/null
+++ b/front/plugins/undiscoverables/README.md
@@ -0,0 +1,27 @@
+## Overview
+
+A plugin allowing for importing Un-Discoverable devices from the settings page.
+The main usecase is to add dumb network gear like unmanaged hubs and switches to the network view.
+There might be other usecases, please let me know.
+
+### Usage
+
+- Go to settings and find Un-Discoverabe Devices in the list of plugins.
+- Enable the plugin by changing the RUN parameter from disabled to `once` or `always_after_scan`.
+- Add the name of your device to the list. (remove the sample entry first)
+- SAVE
+- wait for the next scan to finish
+
+#### Examples:
+Settings:
+
+
+resulting in these devices:
+
+
+Allowing Un-Discoverable devices like hubs, switches or APs to be added to the network view.
+
+
+### Known Limitations
+ - Un-Discoverable Devices always show as offline. That is expected as they can not be discovered by Pi.Alert.
+ - All IPs are set to 0.0.0.0 therefore the "Random MAC" icon might show up.
diff --git a/front/plugins/undiscoverables/config.json b/front/plugins/undiscoverables/config.json
new file mode 100644
index 00000000..de03f76f
--- /dev/null
+++ b/front/plugins/undiscoverables/config.json
@@ -0,0 +1,217 @@
+{
+ "code_name": "undiscoverables",
+ "unique_prefix": "UNDIS",
+ "enabled": true,
+ "data_source": "python-script",
+ "mapped_to_table": "DHCP_Leases",
+
+ "localized": ["display_name", "description", "icon"],
+
+ "display_name": [
+ {
+ "language_code": "en_us",
+ "string": "Un-Discoverable Devices"
+ }
+ ],
+ "icon": [
+ {
+ "language_code": "en_us",
+ "string": ""
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "This plugin is to import undiscoverable devices from a file."
+ }
+ ],
+ "params" : [
+ {
+ "name" : "devices",
+ "type" : "setting",
+ "value" : "UNDIS_devices_to_import"
+ }],
+
+ "settings": [
+ {
+ "function": "RUN",
+ "type": "selecttext",
+ "default_value":"disabled",
+ "options": ["disabled", "once", "always_after_scan"],
+ "localized": ["name", "description"],
+ "name" :[{
+ "language_code":"en_us",
+ "string" : "When to run"
+ }],
+ "description": [{
+ "language_code":"en_us",
+ "string" : "When enabled, \"once\" is the preferred option. It runs at startup and after every save of the config here.
Changes will only show in the devices after the next scan!"
+ }]
+ },
+ {
+ "function": "CMD",
+ "type": "readonly",
+ "default_value": "python3 /home/pi/pialert/front/plugins/undiscoverables/script.py devices={devices}",
+ "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": "integer",
+ "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": "WATCH",
+ "type": "lable",
+ "default_value": [],
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Watched"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "Undiscoverable Devices can not change their status, no watch is enabled."
+ }
+ ]
+ },
+ {
+ "function": "REPORT_ON",
+ "type": "lable",
+ "default_value": [],
+ "options": ["new", "watched-changed", "watched-not-changed"],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Report on"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "No notifications will be sent."
+ }
+ ]
+ },
+ {
+ "function": "devices_to_import",
+ "type": "list",
+ "default_value":["dummy_router"],
+ "options": [],
+ "localized": ["name", "description"],
+ "name" : [{
+ "language_code":"en_us",
+ "string" : "UnDiscoverable Devices"
+ }],
+ "description": [{
+ "language_code":"en_us",
+ "string" : "Devices to be added to the devices list."
+ }]
+ }
+ ],
+
+ "database_column_definitions":
+ [
+ {
+ "column": "Watched_Value1",
+ "mapped_to_column": "DHCP_Name",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value":"",
+ "options": [],
+ "localized": ["name"],
+ "name":[{
+ "language_code":"en_us",
+ "string" : "Device Name"
+ }]
+ },
+ {
+ "column": "Object_PrimaryID",
+ "mapped_to_column": "DHCP_MAC",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "devicemac",
+ "default_value":"",
+ "options": [],
+ "localized": ["name"],
+ "name":[{
+ "language_code":"en_us",
+ "string" : "MAC address"
+ }]
+ },
+ {
+ "column": "Object_SecondaryID",
+ "mapped_to_column": "DHCP_IP",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "deviceip",
+ "default_value":"",
+ "options": [],
+ "localized": ["name"],
+ "name":[{
+ "language_code":"en_us",
+ "string" : "IP"
+ }]
+ } ,
+ {
+ "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",
+ "mapped_to_column": "DHCP_DateTime",
+ "css_classes": "col-sm-2",
+ "show": true,
+ "type": "label",
+ "default_value":"",
+ "options": [],
+ "localized": ["name"],
+ "name":[{
+ "language_code":"en_us",
+ "string" : "Changed"
+ }]
+ }
+ ]
+}
diff --git a/front/plugins/undiscoverables/plugin_helper.py b/front/plugins/undiscoverables/plugin_helper.py
new file mode 100644
index 00000000..e198f30a
--- /dev/null
+++ b/front/plugins/undiscoverables/plugin_helper.py
@@ -0,0 +1,96 @@
+from time import strftime
+
+
+# -------------------------------------------------------------------
+class Plugin_Object:
+ """
+ Plugin_Object class to manage one object introduced by the plugin
+ An object typically is a device but could also be a website or something
+ else that is monitored by the plugin.
+ """
+
+ def __init__(
+ self,
+ primaryId="",
+ secondaryId="",
+ watched1="",
+ watched2="",
+ watched3="",
+ watched4="",
+ extra="",
+ foreignKey="",
+ ):
+ self.pluginPref = ""
+ self.primaryId = primaryId
+ self.secondaryId = secondaryId
+ self.created = strftime("%Y-%m-%d %H:%M:%S")
+ self.changed = ""
+ self.watched1 = watched1
+ self.watched2 = watched2
+ self.watched3 = watched3
+ self.watched4 = watched4
+ self.status = ""
+ self.extra = extra
+ self.userData = ""
+ self.foreignKey = foreignKey
+
+ def write(self):
+ """
+ write the object details as a string in the
+ format required to write the result file
+ """
+ line = "{}|{}|{}|{}|{}|{}|{}|{}|{}\n".format(
+ self.primaryId,
+ self.secondaryId,
+ self.created,
+ self.watched1,
+ self.watched2,
+ self.watched3,
+ self.watched4,
+ self.extra,
+ self.foreignKey,
+ )
+ return line
+
+
+class Plugin_Objects:
+ """
+ Plugin_Objects is the class that manages and holds all the objects created by the plugin.
+ It contains a list of Plugin_Object instances.
+ And can write the required result file.
+ """
+
+ def __init__(self, result_file):
+ self.result_file = result_file
+ self.objects = []
+
+ def add_object(
+ self,
+ primaryId="",
+ secondaryId="",
+ watched1="",
+ watched2="",
+ watched3="",
+ watched4="",
+ extra="",
+ foreignKey="",
+ ):
+ self.objects.append(
+ Plugin_Object(
+ primaryId,
+ secondaryId,
+ watched1,
+ watched2,
+ watched3,
+ watched4,
+ extra,
+ foreignKey,
+ )
+ )
+
+ def write_result_file(self):
+ # print ("writing file: "+self.result_file)
+ with open(self.result_file, mode="w") as fp:
+ for obj in self.objects:
+ fp.write(obj.write())
+ fp.close()
diff --git a/front/plugins/undiscoverables/script.py b/front/plugins/undiscoverables/script.py
new file mode 100644
index 00000000..7f17554d
--- /dev/null
+++ b/front/plugins/undiscoverables/script.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# test script by running python script.py devices=test,dummy
+
+import os
+import pathlib
+import argparse
+
+from plugin_helper import Plugin_Objects
+
+CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
+LOG_FILE = os.path.join(CUR_PATH , 'script.log')
+RESULT_FILE = os.path.join(CUR_PATH , 'last_result.log')
+
+
+
+def main():
+
+ # the script expects a parameter in the format of devices=device1,device2,...
+ parser = argparse.ArgumentParser(description='Import devices from settings')
+ parser.add_argument('devices', action="store", help="list of device names separated by ','")
+ values = parser.parse_args()
+
+ UNDIS_devices = Plugin_Objects( RESULT_FILE )
+
+ if values.devices:
+ for fake_dev in values.devices.split('=')[1].split(','):
+ UNDIS_devices.add_object(
+ primaryId=fake_dev, # MAC (Device Name)
+ secondaryId="0.0.0.0", # IP Address (always 0.0.0.0)
+ watched1=fake_dev, # Device Name
+ watched2="",
+ watched3="",
+ watched4="",
+ extra="",
+ foreignKey="")
+
+ UNDIS_devices.write_result_file()
+
+ return 0
+
+#===============================================================================
+# BEGIN
+#===============================================================================
+if __name__ == '__main__':
+ main()
\ No newline at end of file