mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 01:26:11 -08:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e2559c229 | ||
|
|
c91e428e77 | ||
|
|
ee35f35794 | ||
|
|
7492a07244 | ||
|
|
3f3143452e | ||
|
|
e2e5a10e7e | ||
|
|
85335bcdbb | ||
|
|
93420b1f86 | ||
|
|
b7d60ea818 | ||
|
|
0551cd1eea | ||
|
|
b86f1d75b5 | ||
|
|
89fb5c9b3b | ||
|
|
f5d8a9fc8c | ||
|
|
973cd60893 | ||
|
|
da0130da4b | ||
|
|
c8e494596e | ||
|
|
baec65fde7 | ||
|
|
9f5884c4e7 | ||
|
|
4767dec6b8 | ||
|
|
536ef9ec46 | ||
|
|
fd162ff98a | ||
|
|
0ed24dac0a | ||
|
|
e434a686c6 | ||
|
|
138a899e34 | ||
|
|
ae7533cec0 | ||
|
|
55e398dd10 | ||
|
|
fdd199935a | ||
|
|
346a22f2f6 | ||
|
|
5d64433be0 | ||
|
|
1a3cf49c00 | ||
|
|
9dd456bd2c | ||
|
|
1b9d4223c5 | ||
|
|
2a4ac2f2be | ||
|
|
a2f3666134 | ||
|
|
1435ecac67 | ||
|
|
897112e466 | ||
|
|
31e1116483 | ||
|
|
7da9bf03a3 | ||
|
|
8ad63ba07d | ||
|
|
a3702fed94 | ||
|
|
3e3e8fa797 | ||
|
|
f3b64748aa | ||
|
|
257e46df55 | ||
|
|
3c856c010a | ||
|
|
f87ea210c7 | ||
|
|
d433d8e956 | ||
|
|
879d7b674b | ||
|
|
21d47f5d0d | ||
|
|
e7d5c1e5fe | ||
|
|
5c08b06ace | ||
|
|
bb10b865f9 | ||
|
|
557eb8d09e | ||
|
|
a69ce7b85d | ||
|
|
b5649e3c7b | ||
|
|
1ebae57f48 | ||
|
|
6c619bf6f7 | ||
|
|
cfb4bbe907 | ||
|
|
c708718e78 | ||
|
|
1a02d34e85 | ||
|
|
dcf785b900 | ||
|
|
88bbae7c84 | ||
|
|
9485b5adfb | ||
|
|
e2d475100e | ||
|
|
22d3169d07 | ||
|
|
ebe7b9e9e6 | ||
|
|
78c18aa100 | ||
|
|
bd9f68bb27 | ||
|
|
1e693abfc4 | ||
|
|
e4a64a11bd | ||
|
|
43c57f00d0 | ||
|
|
122bb29e99 | ||
|
|
bc8f95d30c | ||
|
|
be4e0acdfc | ||
|
|
79c47015f4 | ||
|
|
d4b590a9fc | ||
|
|
e018fe2995 | ||
|
|
4aad8c12f8 | ||
|
|
93c45d7157 | ||
|
|
695f1593c6 | ||
|
|
eb7b7b57ab | ||
|
|
e8e8260856 | ||
|
|
50b576134a | ||
|
|
2476a36661 | ||
|
|
2aa984b147 | ||
|
|
16de261477 | ||
|
|
9dfc574bde | ||
|
|
9072c37589 | ||
|
|
095a71bc8f | ||
|
|
2b057d339c | ||
|
|
1e0552cc13 | ||
|
|
eea0bf66db | ||
|
|
0741b396ef | ||
|
|
865f3eabd8 | ||
|
|
f5ba9b524d | ||
|
|
654253c953 | ||
|
|
1711cbfe2d |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.vscode
|
||||
.DS_Store
|
||||
config/*
|
||||
config/pialert.conf
|
||||
db/*
|
||||
db/pialert.db
|
||||
@@ -14,4 +15,6 @@ __pycache__/
|
||||
*$py.class
|
||||
|
||||
**/last_result.log
|
||||
**/script.log
|
||||
**/script.log
|
||||
**/pialert.conf_bak
|
||||
**/pialert.db_bak
|
||||
48
Dockerfile
48
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-slim
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# default UID and GID
|
||||
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
|
||||
@@ -7,15 +7,9 @@ ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
|
||||
# Todo, figure out why using a workdir instead of full paths don't work
|
||||
# Todo, do we still need all these packages? I can already see sudo which isn't needed
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools python3 iproute2 nmap python3-pip zip systemctl usbutils traceroute -y \
|
||||
&& pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi \
|
||||
&& update-alternatives --install /usr/bin/python python /usr/bin/python3 10 \
|
||||
&& apt-get clean autoclean \
|
||||
&& apt-get autoremove \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& rm -rf /var/www/html \
|
||||
&& ln -s /home/pi/pialert/front /var/www/html
|
||||
RUN apt-get update
|
||||
RUN apt-get install sudo -y
|
||||
|
||||
|
||||
# create pi user and group
|
||||
# add root and www-data to pi group so they can r/w files and db
|
||||
@@ -31,24 +25,26 @@ RUN groupadd --gid "${USER_GID}" "${USER}" && \
|
||||
|
||||
COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . /home/pi/pialert/
|
||||
|
||||
# Pi.Alert
|
||||
RUN rm /etc/nginx/sites-available/default \
|
||||
&& ln -s /home/pi/pialert/install/default /etc/nginx/sites-available/default \
|
||||
&& sed -ie 's/listen 80/listen '${PORT}'/g' /etc/nginx/sites-available/default \
|
||||
# run the hardware vendors update
|
||||
&& /home/pi/pialert/back/update_vendors.sh \
|
||||
# Create a backup of the pialert.conf to be used if the user didn't supply a configuration file
|
||||
&& cp /home/pi/pialert/config/pialert.conf /home/pi/pialert/back/pialert.conf_bak \
|
||||
# Create a backup of the pialert.db to be used if the user didn't supply a database
|
||||
&& cp /home/pi/pialert/db/pialert.db /home/pi/pialert/back/pialert.db_bak \
|
||||
# Create a buildtimestamp.txt to later check if a new version was released
|
||||
&& date +%s > /home/pi/pialert/front/buildtimestamp.txt
|
||||
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.sh file as well ❗
|
||||
|
||||
RUN apt-get install -y \
|
||||
tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \
|
||||
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \
|
||||
python3 iproute2 nmap python3-pip zip systemctl usbutils traceroute
|
||||
|
||||
# Alternate dependencies
|
||||
RUN apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y
|
||||
RUN phpenmod -v 8.2 sqlite3
|
||||
|
||||
# Setup virtual python environment and use pip3 to install packages
|
||||
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 requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet"
|
||||
|
||||
# Create a buildtimestamp.txt to later check if a new version was released
|
||||
RUN date +%s > /home/pi/pialert/front/buildtimestamp.txt
|
||||
|
||||
CMD ["/home/pi/pialert/dockerfiles/start.sh"]
|
||||
|
||||
|
||||
|
||||
|
||||
## command to build docker: DOCKER_BUILDKIT=1 docker build . --iidfile dockerID
|
||||
|
||||
@@ -11,9 +11,9 @@ Scans for devices, port changes on your WIFI/LAN and alerts you if unknown devic
|
||||
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Docker guide](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [All Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs) |
|
||||
|----------------------|----------------------| ----------------------| ----------------------|
|
||||
|
||||
## Why PiAlert❓ Isn't this scary 👻...
|
||||
## Why PiAlert❓
|
||||
|
||||
...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 😖.
|
||||
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 🔐_.
|
||||
|
||||
@@ -21,7 +21,9 @@ _PiAlert combines several network and other scanning tools 🔍 with notificatio
|
||||
|
||||
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 and handle the results and notifications in PiAlert. Check available [Plugins & Instructions](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins). Looking forward to your contributions if you decide to share your work with the community ❤.
|
||||
Extend the app if you want to create your own scanner and handle the results and notifications in PiAlert. Check available [Plugins & Instructions](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins).
|
||||
|
||||
Looking forward to your contributions if you decide to share your work with the community ❤.
|
||||
|
||||
| ![Main screen][main] | ![Screen 1][screen1] | ![Screen 5][screen5] |
|
||||
|----------------------|----------------------| ----------------------|
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Event Type</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device name</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Comments</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device Vendor</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
@@ -54,6 +55,7 @@
|
||||
<td>New Device</td>
|
||||
<td>(name not found)</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
@@ -62,6 +64,7 @@
|
||||
<td>New Device</td>
|
||||
<td>(name not found)</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
@@ -83,6 +86,7 @@
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Event Type</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device name</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Comments</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device Vendor</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Report Date: <REPORT_DATE>
|
||||
Server: <SERVER_NAME>
|
||||
|
||||
<SECTION_NEW_DEVICES>
|
||||
<SECTION_DEVICES_DOWN>
|
||||
<SECTION_EVENTS>
|
||||
<NEW_DEVICES_TABLE>
|
||||
<DOWN_DEVICES_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PLUGINS_TABLE>
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
# /usr/share/ieee-data
|
||||
# /var/lib/ieee-data
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run update_vendors.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
echo Updating... /usr/share/ieee-data/
|
||||
@@ -51,6 +53,9 @@ sudo cp *.txt 2_backup
|
||||
sudo get-iab -v
|
||||
sudo get-oui -v
|
||||
|
||||
# make files readable
|
||||
sudo chmod +r /usr/share/arp-scan/ieee-oui.txt
|
||||
|
||||
# Update from ieee website
|
||||
# sudo get-iab -v -u http://standards-oui.ieee.org/iab/iab.txt
|
||||
# sudo get-oui -v -u http://standards-oui.ieee.org/oui/oui.txt
|
||||
|
||||
@@ -1,87 +1,76 @@
|
||||
[
|
||||
{
|
||||
"headers": {
|
||||
"host": "192.168.1.82:5678",
|
||||
"user-agent": "curl/7.74.0",
|
||||
"accept": "*/*",
|
||||
"content-type": "application/json",
|
||||
"content-length": "872"
|
||||
},
|
||||
"params": {},
|
||||
"query": {},
|
||||
"body": {
|
||||
"username": "Pi.Alert",
|
||||
"text": "There are new notifications",
|
||||
"attachments": [
|
||||
{
|
||||
"title": "Pi.Alert Notifications",
|
||||
"title_link": "",
|
||||
"text": {
|
||||
"internet": [],
|
||||
"new_devices": [{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.1",
|
||||
"Event Type": "New Device",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}],
|
||||
"down_devices": [],
|
||||
"events": [{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.92",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}, {
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.150",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}],
|
||||
"ports": [{
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "22/tcp",
|
||||
"State": "open",
|
||||
"Service": "ssh",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "53/tcp",
|
||||
"State": "open",
|
||||
"Service": "domain",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "80/tcp",
|
||||
"State": "open",
|
||||
"Service": "http",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "443/tcp",
|
||||
"State": "open",
|
||||
"Service": "https",
|
||||
"Extra": ""
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
{
|
||||
"headers": {
|
||||
"host": "192.168.1.82:5678",
|
||||
"user-agent": "curl/7.74.0",
|
||||
"accept": "*/*",
|
||||
"content-type": "application/json",
|
||||
"content-length": "872"
|
||||
},
|
||||
"params": {},
|
||||
"query": {},
|
||||
"body": {
|
||||
"username": "Pi.Alert",
|
||||
"text": "There are new notifications",
|
||||
"attachments": [
|
||||
{
|
||||
"title": "Pi.Alert Notifications",
|
||||
"title_link": "",
|
||||
"text": {
|
||||
"internet": [],
|
||||
"new_devices": [
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.1",
|
||||
"Event Type": "New Device",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
}
|
||||
],
|
||||
"down_devices": [],
|
||||
"events": [
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.92",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
},
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.150",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
}
|
||||
],
|
||||
"plugins": [
|
||||
{
|
||||
"Index": 138,
|
||||
"Plugin": "INTRSPD",
|
||||
"Object_PrimaryID": "Speedtest",
|
||||
"Object_SecondaryID": "2023-10-08 02:01:16+02:00",
|
||||
"DateTimeCreated": "2023-10-08 02:01:16",
|
||||
"DateTimeChanged": "2023-10-08 02:32:15",
|
||||
"Watched_Value1": "-1",
|
||||
"Watched_Value2": "-1",
|
||||
"Watched_Value3": "null",
|
||||
"Watched_Value4": "null",
|
||||
"Status": "missing-in-last-scan",
|
||||
"Extra": "null",
|
||||
"UserData": "null",
|
||||
"ForeignKey": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
2
config/.gitignore
vendored
Executable file
2
config/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
db/.gitignore
vendored
Executable file
2
db/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -22,19 +22,21 @@ services:
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp1.leases:/mnt/dhcp1.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_full.leases:/etc/pihole/dhcp.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_2.leases:/etc/pihole/dhcp2.leases
|
||||
- ${APP_DATA_LOCATION}/pihole/etc-pihole/pihole-FTL.db:/etc/pihole/pihole-FTL.db
|
||||
- ${DEV_LOCATION}/pialert:/home/pi/pialert/pialert
|
||||
- ${DEV_LOCATION}/back/report_template.html:/home/pi/pialert/back/report_template.html
|
||||
- ${DEV_LOCATION}/back/report_template_new_version.html:/home/pi/pialert/back/report_template_new_version.html
|
||||
- ${DEV_LOCATION}/back/report_template.txt:/home/pi/pialert/back/report_template.txt
|
||||
- ${DEV_LOCATION}/pialert:/home/pi/pialert/pialert
|
||||
- ${DEV_LOCATION}/dockerfiles:/home/pi/pialert/dockerfiles
|
||||
- ${APP_DATA_LOCATION}/pialert/php.ini:/etc/php/7.4/fpm/php.ini
|
||||
# - ${DEV_LOCATION}/front/api:/home/pi/pialert/front/api
|
||||
- ${APP_DATA_LOCATION}/pialert/php.ini:/etc/php/8.2/fpm/php.ini
|
||||
- ${DEV_LOCATION}/install:/home/pi/pialert/install
|
||||
- ${DEV_LOCATION}/front/css:/home/pi/pialert/front/css
|
||||
- ${DEV_LOCATION}/front/lib/AdminLTE:/home/pi/pialert/front/lib/AdminLTE
|
||||
- ${DEV_LOCATION}/front/js:/home/pi/pialert/front/js
|
||||
- ${DEV_LOCATION}/dockerfiles/start.sh:/home/pi/pialert/dockerfiles/start.sh
|
||||
- ${DEV_LOCATION}/dockerfiles/user-mapping.sh:/home/pi/pialert/dockerfiles/user-mapping.sh
|
||||
- ${DEV_LOCATION}/install/install.sh:/home/pi/pialert/install/install.sh
|
||||
- ${DEV_LOCATION}/install/install_dependencies.sh:/home/pi/pialert/install/install_dependencies.sh
|
||||
- ${DEV_LOCATION}/front/api:/home/pi/pialert/front/api
|
||||
- ${DEV_LOCATION}/front/php:/home/pi/pialert/front/php
|
||||
- ${DEV_LOCATION}/front/php:/home/pi/pialert/front/php
|
||||
- ${DEV_LOCATION}/front/deviceDetails.php:/home/pi/pialert/front/deviceDetails.php
|
||||
- ${DEV_LOCATION}/front/deviceDetailsTools.php:/home/pi/pialert/front/deviceDetailsTools.php
|
||||
- ${DEV_LOCATION}/front/devices.php:/home/pi/pialert/front/devices.php
|
||||
|
||||
@@ -35,6 +35,7 @@ docker run -d --rm --network=host \
|
||||
| Variable | Description | Default |
|
||||
| :------------- |:-------------| -----:|
|
||||
| `PORT` |Port of the web interface | `20211` |
|
||||
| `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` |
|
||||
|
||||
@@ -1,33 +1,123 @@
|
||||
#!/bin/sh
|
||||
/home/pi/pialert/dockerfiles/user-mapping.sh
|
||||
#!/bin/bash
|
||||
|
||||
# # if custom variables not set we do not need to do anything
|
||||
# if [ -n "${TZ}" ]; then
|
||||
# FILECONF=/home/pi/pialert/config/pialert.conf
|
||||
# if [ -f "$FILECONF" ]; then
|
||||
# sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/config/pialert.conf
|
||||
# else
|
||||
# sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/back/pialert.conf_bak
|
||||
# fi
|
||||
# fi
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run start.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
|
||||
INSTALL_DIR=/home/pi # Specify the installation directory here
|
||||
|
||||
# if custom variables not set we do not need to do anything
|
||||
if [ -n "${TZ}" ]; then
|
||||
FILECONF=$INSTALL_DIR/pialert/config/pialert.conf
|
||||
if [ -f "$FILECONF" ]; then
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" $INSTALL_DIR/pialert/config/pialert.conf
|
||||
else
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" $INSTALL_DIR/pialert/back/pialert.conf_bak
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if script is run as root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root. Please use 'sudo'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run setup scripts
|
||||
echo "[INSTALL] Run setup scripts"
|
||||
|
||||
"$INSTALL_DIR/pialert/dockerfiles/user-mapping.sh"
|
||||
"$INSTALL_DIR/pialert/install/install_dependencies.sh" # if modifying this file transfer the chanegs into the root Dockerfile as well!
|
||||
|
||||
# Change port number if set
|
||||
if [ -n "${PORT}" ]; then
|
||||
sed -ie 's/listen 20211/listen '${PORT}'/g' /etc/nginx/sites-available/default
|
||||
fi
|
||||
|
||||
# I hope this will fix DB permission issues going forward
|
||||
FILEDB=/home/pi/pialert/db/pialert.db
|
||||
if [ -f "$FILEDB" ]; then
|
||||
chown -R www-data:www-data /home/pi/pialert/db/pialert.db
|
||||
echo "[INSTALL] Setup NGINX"
|
||||
|
||||
# Remove /html folder if exists
|
||||
sudo rm -R /var/www/html
|
||||
|
||||
# create symbolic link to the pialert install directory
|
||||
ln -s $INSTALL_DIR/pialert/front /var/www/html
|
||||
# remove dfault NGINX site
|
||||
sudo rm /etc/nginx/sites-available/default
|
||||
# create symbolic link to NGINX configuaration coming with PiAlert
|
||||
sudo ln -s "$INSTALL_DIR/pialert/install/default" /etc/nginx/sites-available/default
|
||||
# use user-supplied port
|
||||
sudo sed -i 's/listen 80/listen '"$PORT"'/g' /etc/nginx/sites-available/default
|
||||
|
||||
# Change web interface address if set
|
||||
if [ -n "${LISTEN_ADDR}" ]; then
|
||||
sed -ie 's/listen /listen '${LISTEN_ADDR}:'/g' /etc/nginx/sites-available/default
|
||||
fi
|
||||
|
||||
chmod -R a+rw /home/pi/pialert/front/log
|
||||
chmod -R a+rw /home/pi/pialert/config
|
||||
# Run the hardware vendors update at least once
|
||||
echo "[INSTALL] Run the hardware vendors update"
|
||||
|
||||
/etc/init.d/php7.4-fpm start
|
||||
# Define the path to ieee-oui.txt and ieee-iab.txt
|
||||
oui_file="/usr/share/arp-scan/ieee-oui.txt"
|
||||
|
||||
# Check if ieee-oui.txt or ieee-iab.txt exist
|
||||
if [ -f "$oui_file" ]; then
|
||||
echo "The file ieee-oui.txt exists. Skipping update_vendors.sh..."
|
||||
else
|
||||
echo "The file ieee-oui.txt does not exist. Running update_vendors..."
|
||||
|
||||
# Run the update_vendors.sh script
|
||||
if [ -f "$INSTALL_DIR/pialert/back/update_vendors.sh" ]; then
|
||||
"$INSTALL_DIR/pialert/back/update_vendors.sh"
|
||||
else
|
||||
echo "update_vendors.sh script not found in $INSTALL_DIR."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fixing file permissions
|
||||
echo "[INSTALL] Fixing file permissions"
|
||||
|
||||
|
||||
chmod -R a+rwx /var/www/html
|
||||
chmod -R a+rw $INSTALL_DIR/pialert/front/log
|
||||
chmod -R a+rwx $INSTALL_DIR
|
||||
|
||||
FILEDB=$INSTALL_DIR/pialert/db/pialert.db
|
||||
|
||||
if [ -f "$FILEDB" ]; then
|
||||
chown -R www-data:www-data $INSTALL_DIR/pialert/db/pialert.db
|
||||
fi
|
||||
|
||||
echo "[INSTALL] Copy starter pialert.db and pialert.conf if they don't exist"
|
||||
|
||||
# Copy starter pialert.db and pialert.conf if they don't exist
|
||||
cp -n "$INSTALL_DIR/pialert/back/pialert.conf" "$INSTALL_DIR/pialert/config/pialert.conf"
|
||||
cp -n "$INSTALL_DIR/pialert/back/pialert.db" "$INSTALL_DIR/pialert/db/pialert.db"
|
||||
|
||||
|
||||
chmod -R a+rwx $INSTALL_DIR # second time after we copied the files
|
||||
chmod -R a+rw $INSTALL_DIR/pialert/config
|
||||
sudo chgrp -R www-data $INSTALL_DIR/pialert
|
||||
|
||||
# Check if buildtimestamp.txt doesn't exist
|
||||
if [ ! -f "$INSTALL_DIR/pialert/front/buildtimestamp.txt" ]; then
|
||||
# Create buildtimestamp.txt
|
||||
date +%s > "$INSTALL_DIR/pialert/front/buildtimestamp.txt"
|
||||
fi
|
||||
|
||||
|
||||
# start PHP
|
||||
/etc/init.d/php8.2-fpm start
|
||||
/etc/init.d/nginx start
|
||||
|
||||
# cron -f
|
||||
#python /home/pi/pialert/back/pialert.py
|
||||
# echo "[DEBUG] DATA MONKEY VERSION ..."
|
||||
python /home/pi/pialert/pialert/
|
||||
# Start Nginx and your application to start at boot (if needed)
|
||||
# systemctl start nginx
|
||||
# systemctl enable nginx
|
||||
|
||||
# # systemctl enable pi-alert
|
||||
# sudo systemctl restart nginx
|
||||
|
||||
# Activate the virtual python environment
|
||||
source myenv/bin/activate
|
||||
|
||||
# Start the PiAlert python script
|
||||
python $INSTALL_DIR/pialert/pialert/
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run user-mapping.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
if [ -z "${USER}" ]; then
|
||||
echo "We need USER to be set!"; exit 100
|
||||
fi
|
||||
@@ -9,7 +13,7 @@ if [ -z "${HOST_USER_ID}" -a -z "${HOST_USER_GID}" ]; then
|
||||
echo "Nothing to do here." ; exit 0
|
||||
fi
|
||||
|
||||
# reset user_?id to either new id or if empty old (still one of above
|
||||
# reset user_id to either new id or if empty old (still one of above
|
||||
# might not be set)
|
||||
USER_ID=${HOST_USER_ID:=$USER_ID}
|
||||
USER_GID=${HOST_USER_GID:=$USER_GID}
|
||||
@@ -21,6 +25,12 @@ array=( ${LINE//:/ } )
|
||||
# home is 5th element
|
||||
USER_HOME=${array[4]}
|
||||
|
||||
# print debug output
|
||||
echo USER_ID : ${USER_ID};
|
||||
echo USER_GID : ${USER_GID};
|
||||
echo USER_HOME: ${USER_HOME};
|
||||
echo TZ : ${TZ};
|
||||
|
||||
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*:[0-9]*/${USER}:\1:${USER_ID}:${USER_GID}/" /etc/passwd
|
||||
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*/${USER}:\1:${USER_GID}/" /etc/group
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ To edit device information:
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> [Bulk-edit devices](/docs/DEVICES_BULK_EDITING.md) by using the `CSV Export` functionality in the `Maintenance` section.
|
||||
> [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.
|
||||
|
||||
|
||||
![Device Details][screen1]
|
||||
|
||||
0
docs/HW_INSTALL.md
Normal file → Executable file
0
docs/HW_INSTALL.md
Normal file → Executable file
@@ -1,6 +1,6 @@
|
||||
## Icons overview
|
||||
|
||||
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 (I have an unblockable [sponsorship goal](https://github.com/sponsors/jokob-sk) to add the material design icon pack).
|
||||
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.
|
||||
|
||||

|
||||
|
||||
@@ -8,6 +8,8 @@ Icons are used to visually distinguish devices in the app in most of the device
|
||||
|
||||
You can assign icons individually on each device in the Details tab.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- 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:
|
||||
|
||||
@@ -346,5 +346,134 @@ location ^~ /pialert/ {
|
||||
```
|
||||
|
||||
|
||||
## Traefik
|
||||
|
||||
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/Pi.Alert/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/.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik
|
||||
container_name: traefik
|
||||
command:
|
||||
- "--api=true"
|
||||
- "--api.insecure=true"
|
||||
- "--api.dashboard=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--providers.file.filename=/traefik-config/dynamic.toml"
|
||||
- "--providers.file.watch=true"
|
||||
- "--log.level=ERROR"
|
||||
- "--certificatesresolvers.section31.acme.email=postmaster@domain.com"
|
||||
- "--certificatesresolvers.section31.acme.storage=/traefik-config/acme.json"
|
||||
- "--certificatesresolvers.section31.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.section31.acme.httpchallenge.entrypoint=web"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- /appl/docker/traefik/config:/traefik-config
|
||||
depends_on:
|
||||
- authelia
|
||||
restart: unless-stopped
|
||||
authelia:
|
||||
container_name: authelia
|
||||
image: authelia/authelia:latest
|
||||
ports:
|
||||
- "9091:9091"
|
||||
volumes:
|
||||
- /appl/docker/authelia:/config
|
||||
restart: u
|
||||
nless-stopped
|
||||
```
|
||||
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for Pi.Alert:
|
||||
The following are self-defined keywords, everything else is traefik keywords:
|
||||
- pialert-router
|
||||
- pialert-service
|
||||
- auth
|
||||
- pialert-stripprefix
|
||||
|
||||
|
||||
```toml
|
||||
[http.routers]
|
||||
[http.routers.pialert-router]
|
||||
entryPoints = ["websecure"]
|
||||
rule = "Host(`www.domain.com`) && PathPrefix(`/pialert`)"
|
||||
service = "pialert-service"
|
||||
middlewares = "auth,pialert-stripprefix"
|
||||
[http.routers.pialert-router.tls]
|
||||
certResolver = "section31"
|
||||
[[http.routers.pialert-router.tls.domains]]
|
||||
main = "www.domain.com"
|
||||
|
||||
[http.services]
|
||||
[http.services.pialert-service]
|
||||
[[http.services.pialert-service.loadBalancer.servers]]
|
||||
url = "http://internal-ip-address:20211/"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.auth.forwardAuth]
|
||||
address = "http://authelia:9091/api/verify?rd=https://www.domain.com/authelia/"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["Remote-User", "Remote-Groups", "Remote-Name", "Remote-Email"]
|
||||
[http.middlewares.pialert-stripprefix.stripprefix]
|
||||
prefixes = "/pialert"
|
||||
forceSlash = false
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
Default-file:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80 default_server;
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
#rewrite /pialert/(.*) / permanent;
|
||||
add_header X-Forwarded-Prefix "/pialert" always;
|
||||
proxy_set_header X-Forwarded-Prefix "/pialert";
|
||||
|
||||
location ~* \.php$ {
|
||||
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_connect_timeout 75;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_read_timeout 600;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Mapping the updated file (on the local filesystem at `/appl/docker/pialert/default`) into the docker container:
|
||||
|
||||
|
||||
```bash
|
||||
docker run -d --rm --network=host \
|
||||
--name=pi.alert \
|
||||
-v /appl/docker/pialert/config:/home/pi/pialert/config \
|
||||
-v /appl/docker/pialert/db:/home/pi/pialert/db \
|
||||
-v /appl/docker/pialert/default:/etc/nginx/sites-available/default \
|
||||
-e TZ=Europe/Amsterdam \
|
||||
-e PORT=20211 \
|
||||
jokobsk/pi.alert:latest
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Specify the network filter (which **significantly** speeds up the scan process).
|
||||
|
||||
**Example value: `--interface=eth0`**
|
||||
|
||||
The adapter will probably be `eth0` or `eth1`. (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`).
|
||||
|
||||
|
||||
BIN
docs/img/ICONS/device_icons_preview.gif
Executable file
BIN
docs/img/ICONS/device_icons_preview.gif
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
@@ -173,6 +173,7 @@
|
||||
@media (max-width: 767px) {
|
||||
.main-header .logo {
|
||||
width: 100%;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.main-header .navbar {
|
||||
@@ -584,8 +585,24 @@ height: 50px;
|
||||
.infobox_label {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
/* --------------------------------------------------------- */
|
||||
/* report */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/*settings*/
|
||||
#notificationData textarea{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#notificationData pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
|
||||
.string { color: green; }
|
||||
.number { color: darkorange; }
|
||||
.boolean { color: blue; }
|
||||
.null { color: magenta; }
|
||||
.key { color: red; }
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* settings */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* hide on mobile */
|
||||
@@ -623,6 +640,52 @@ height: 50px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settingswrap .enabled-disabled-icon
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.settings-group
|
||||
{
|
||||
font-size: 20px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 9px;
|
||||
}
|
||||
|
||||
.overview-section .small-box .icon
|
||||
{
|
||||
font-size: 38px;
|
||||
top:0px;
|
||||
}
|
||||
|
||||
.overview-section
|
||||
{
|
||||
border: solid;
|
||||
border-width: medium;
|
||||
border-width: medium;
|
||||
border-width: 1px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 3px;
|
||||
|
||||
}
|
||||
|
||||
.settings-group i{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.overview-group
|
||||
{
|
||||
font-size: 20px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 9px;
|
||||
|
||||
}
|
||||
|
||||
.overview-group i{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
.table_row {
|
||||
padding: 3px;
|
||||
width:100%;
|
||||
@@ -672,6 +735,18 @@ height: 50px;
|
||||
|
||||
/* Settings */
|
||||
|
||||
#settingsPage .overview-setting-value{
|
||||
display:unset;
|
||||
}
|
||||
#settingsPage .panel-title{
|
||||
/* display: inline-block; */
|
||||
/* width: 120px; */
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.settings_content {
|
||||
padding: 10px;
|
||||
/* background-color: #272c30; */
|
||||
@@ -718,6 +793,10 @@ input[readonly] {
|
||||
}
|
||||
|
||||
/* Devices */
|
||||
#txtIconFA {
|
||||
min-width: 18px;
|
||||
}
|
||||
|
||||
.drp-edit
|
||||
{
|
||||
cursor: pointer;
|
||||
@@ -795,7 +874,8 @@ input[readonly] {
|
||||
#networkTree .netPort
|
||||
{
|
||||
float:left;
|
||||
display:inline;
|
||||
display:inline;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#networkTree .portBckgIcon
|
||||
@@ -816,14 +896,14 @@ input[readonly] {
|
||||
{
|
||||
width: 25px;;
|
||||
float:left;
|
||||
display:inline;
|
||||
display:inline;
|
||||
text-align: center;
|
||||
}
|
||||
#networkTree .netCollapse
|
||||
{
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin-left: 170px;
|
||||
top: -3px;
|
||||
margin-left: 170px;
|
||||
font-size: large;
|
||||
left: -15px;
|
||||
}
|
||||
@@ -883,30 +963,43 @@ input[readonly] {
|
||||
|
||||
/*Hidden special button*/
|
||||
|
||||
@media (max-width: 464px) {
|
||||
@media (max-width: 365px) {
|
||||
#back-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 432px) {
|
||||
@media (max-width: 335px) {
|
||||
#next-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
@media (max-width: 300px) {
|
||||
#reload-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 365px) {
|
||||
@media (max-width: 300px) {
|
||||
#fullscreen-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.header-server-time {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#settingsPage .small-box .inner .card-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Spin
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="txtName" type="text" value="--">
|
||||
<span class="input-group-addon"><i class="fa fa-pencil pointer" onclick="editDrp('txtName');"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -196,9 +196,9 @@
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="txtIcon" type="text" value="--">
|
||||
<span class="input-group-addon"><i class="fa" id="txtIconFA" onclick="editDrp('txtIcon');"></i></span>
|
||||
<input class="form-control" id="txtIcon" type="text" value="--">
|
||||
<span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span>
|
||||
<span class="input-group-addon"><i class="fa fa-pencil pointer" onclick="editDrp('txtIcon');"></i></span>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fa fa-caret-down"></span>
|
||||
@@ -325,7 +325,7 @@
|
||||
<div class="form-group" title="<?= lang('DevDetail_Network_Node_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<div class="input-group parentNetworkNode">
|
||||
|
||||
<input class="form-control" id="txtNetworkNodeMac" type="text" value="--">
|
||||
<span class="input-group-addon"><i title="<?= lang('DevDetail_GoToNetworkNode');?>" class="fa fa-square-up-right pointer" onclick="goToNetworkNode('txtNetworkNodeMac');"></i></span>
|
||||
@@ -749,6 +749,11 @@ function main () {
|
||||
}
|
||||
});
|
||||
|
||||
// Show device icon as it changes
|
||||
$('#txtIcon').on('change input', function() {
|
||||
$('#txtIconFA').removeClass().addClass(`fa fa-${$(this).val()} pointer`)
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1172,7 +1177,7 @@ function getDeviceData (readAllData=false) {
|
||||
$("body").css ("cursor", "progress");
|
||||
}
|
||||
|
||||
// get data from server
|
||||
// get data from server
|
||||
$.get('php/server/devices.php?action=getDeviceData&mac='+ mac + '&period='+ period, function(data) {
|
||||
|
||||
var deviceData = JSON.parse(data);
|
||||
@@ -1285,7 +1290,8 @@ function getDeviceData (readAllData=false) {
|
||||
$('#txtOwner').val (deviceData['dev_Owner']);
|
||||
$('#txtDeviceType').val (deviceData['dev_DeviceType']);
|
||||
$('#txtVendor').val (deviceData['dev_Vendor']);
|
||||
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'laptop'));
|
||||
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'laptop'));
|
||||
$('#txtIcon').trigger('change')
|
||||
|
||||
if (deviceData['dev_Favorite'] == 1) {$('#chkFavorite').iCheck('check');} else {$('#chkFavorite').iCheck('uncheck');}
|
||||
$('#txtGroup').val (deviceData['dev_Group']);
|
||||
@@ -1295,8 +1301,8 @@ function getDeviceData (readAllData=false) {
|
||||
$('#txtNetworkNodeMac').attr ('data-mynodemac', deviceData['dev_Network_Node_MAC_ADDR']);
|
||||
$('#txtNetworkPort').val (deviceData['dev_Network_Node_port']);
|
||||
// disabling network node configuration if root Internet node
|
||||
$('#txtNetworkNodeMac').prop('readonly', mac == 'Internet' );
|
||||
$('#txtNetworkPort').prop('readonly', mac == 'Internet' );
|
||||
toggleNetworkConfiguration(mac == 'Internet')
|
||||
|
||||
|
||||
$('#txtFirstConnection').val (deviceData['dev_FirstConnection']);
|
||||
$('#txtLastConnection').val (deviceData['dev_LastConnection']);
|
||||
@@ -1398,8 +1404,6 @@ function performSwitch(direction)
|
||||
|
||||
getDeviceData (true);
|
||||
|
||||
// reload current tab
|
||||
reloadTab()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1702,6 +1706,7 @@ function setTextValue (textElement, textValue) {
|
||||
$('#'+textElement).attr ('data-myvalue', textValue);
|
||||
$('#'+textElement).val (textValue);
|
||||
}
|
||||
$('#'+textElement).trigger('change')
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1796,15 +1801,27 @@ window.onload = function async()
|
||||
{
|
||||
initializeTabsNew();
|
||||
|
||||
reloadTab();
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
function reloadTab()
|
||||
// Disables network configuration for the root node
|
||||
function toggleNetworkConfiguration(disable)
|
||||
{
|
||||
// tab loaded without switching
|
||||
$('#txtNetworkNodeMac').prop('readonly', true ); // disable direct input as should only be selected via the dropdown
|
||||
|
||||
if(disable)
|
||||
{
|
||||
$('#txtNetworkNodeMac').val(getString('Network_Root_Unconfigurable'));
|
||||
$('#txtNetworkPort').val(getString('Network_Root_Unconfigurable'));
|
||||
$('#txtNetworkPort').prop('readonly', true );
|
||||
$('.parentNetworkNode .input-group-btn').hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#txtNetworkPort').prop('readonly', false );
|
||||
$('.parentNetworkNode .input-group-btn').show();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<!-- top small box 1 ------------------------------------------------------- -->
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('all');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('all');">
|
||||
<div class="small-box bg-aqua">
|
||||
<div class="inner"><h3 id="devicesAll"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_AllDevices');?></p>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<!-- top small box 2 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('connected');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('connected');">
|
||||
<div class="small-box bg-green">
|
||||
<div class="inner"><h3 id="devicesConnected"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Connected');?></p>
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
<!-- top small box 3 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('favorites');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('favorites');">
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner"><h3 id="devicesFavorites"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Favorites');?></p>
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
<!-- top small box 4 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('new');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('new');">
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner"><h3 id="devicesNew"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_NewDevices');?></p>
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
<!-- top small box 5 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('down');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('down');">
|
||||
<div class="small-box bg-red">
|
||||
<div class="inner"><h3 id="devicesDown"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_DownAlerts');?></p>
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
<!-- top small box 6 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('archived');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('archived');">
|
||||
<div class="small-box bg-gray top_small_box_gray_text">
|
||||
<div class="inner"><h3 id="devicesArchived"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Archived');?></p>
|
||||
@@ -198,9 +198,30 @@
|
||||
var tableRows = 10;
|
||||
var tableOrder = [[3,'desc'], [0,'asc']];
|
||||
|
||||
var tableColumnHide = [];
|
||||
var columnsStr = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]';
|
||||
var tableColumnOrder = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
|
||||
var tableColumnVisible = tableColumnOrder;
|
||||
//initialize the table headers in the correct order
|
||||
var headersDefaultOrder = [ getString('Device_TableHead_Name'),
|
||||
getString('Device_TableHead_Owner'),
|
||||
getString('Device_TableHead_Type'),
|
||||
getString('Device_TableHead_Icon'),
|
||||
getString('Device_TableHead_Favorite'),
|
||||
getString('Device_TableHead_Group'),
|
||||
getString('Device_TableHead_FirstSession'),
|
||||
getString('Device_TableHead_LastSession'),
|
||||
getString('Device_TableHead_LastIP'),
|
||||
getString('Device_TableHead_MAC'),
|
||||
getString('Device_TableHead_Status'),
|
||||
getString('Device_TableHead_MAC_full'),
|
||||
getString('Device_TableHead_LastIPOrder'),
|
||||
getString('Device_TableHead_Rowid'),
|
||||
getString('Device_TableHead_Parent_MAC'),
|
||||
getString('Device_TableHead_Connected_Devices'),
|
||||
getString('Device_TableHead_Location'),
|
||||
getString('Device_TableHead_Vendor')
|
||||
];
|
||||
|
||||
// Read parameters & Initialize components
|
||||
main();
|
||||
@@ -233,29 +254,6 @@ function main () {
|
||||
// save the columns order in the Devices page
|
||||
tableColumnOrder = numberArrayFromString(data);
|
||||
|
||||
|
||||
|
||||
//initialize the table headers in the correct order
|
||||
var headersDefaultOrder = [ '<?= lang('Device_TableHead_Name');?>',
|
||||
'<?= lang('Device_TableHead_Owner');?>',
|
||||
'<?= lang('Device_TableHead_Type');?>',
|
||||
'<?= lang('Device_TableHead_Icon');?>',
|
||||
'<?= lang('Device_TableHead_Favorite');?>',
|
||||
'<?= lang('Device_TableHead_Group');?>',
|
||||
'<?= lang('Device_TableHead_FirstSession');?>',
|
||||
'<?= lang('Device_TableHead_LastSession');?>',
|
||||
'<?= lang('Device_TableHead_LastIP');?>',
|
||||
'<?= lang('Device_TableHead_MAC');?>',
|
||||
'<?= lang('Device_TableHead_Status');?>',
|
||||
'<?= lang('Device_TableHead_MAC_full');?>',
|
||||
'<?= lang('Device_TableHead_LastIPOrder');?>',
|
||||
'<?= lang('Device_TableHead_Rowid');?>',
|
||||
'<?= lang('Device_TableHead_Parent_MAC');?>',
|
||||
'<?= lang('Device_TableHead_Connected_Devices');?>',
|
||||
'<?= lang('Device_TableHead_Location');?>',
|
||||
'<?= lang('Device_TableHead_Vendor');?>'
|
||||
];
|
||||
|
||||
html = '';
|
||||
|
||||
for(index = 0; index < tableColumnOrder.length; index++)
|
||||
@@ -290,8 +288,7 @@ function main () {
|
||||
initializeDatatable();
|
||||
|
||||
// query data
|
||||
getDevicesTotals();
|
||||
getDevicesList (deviceStatus);
|
||||
getDevicesTotals();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -299,8 +296,6 @@ function main () {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
var tableColumnHide = [];
|
||||
|
||||
// mapping the default order to the user specified one
|
||||
function mapIndx(oldIndex)
|
||||
{
|
||||
@@ -314,8 +309,78 @@ function mapIndx(oldIndex)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Define a function to filter data based on deviceStatus
|
||||
function filterDataByStatus(data, status) {
|
||||
return data.filter(function(item) {
|
||||
switch (status) {
|
||||
case 'all':
|
||||
return true; // Include all items for 'all' status
|
||||
case 'connected':
|
||||
return item.dev_PresentLastScan === 1;
|
||||
case 'favorites':
|
||||
return item.dev_Favorite === 1;
|
||||
case 'new':
|
||||
return item.dev_NewDevice === 1;
|
||||
case 'down':
|
||||
return item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown === 1;
|
||||
case 'archived':
|
||||
return item.dev_Archived === 1;
|
||||
default:
|
||||
return true; // Include all items for unknown statuses
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDeviceStatus(item)
|
||||
{
|
||||
if(item.dev_PresentLastScan === 1)
|
||||
{
|
||||
return 'On-line';
|
||||
}
|
||||
else if(item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown === 1)
|
||||
{
|
||||
return 'Down';
|
||||
}
|
||||
else if(item.dev_NewDevice === 1)
|
||||
{
|
||||
return 'New';
|
||||
}
|
||||
else if(item.dev_Archived === 1)
|
||||
{
|
||||
return 'Archived';
|
||||
}
|
||||
else if(item.dev_PresentLastScan === 0)
|
||||
{
|
||||
return 'Off-line';
|
||||
}
|
||||
|
||||
return "Unknown status"
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function initializeDatatable (status) {
|
||||
|
||||
// Save status selected
|
||||
deviceStatus = status;
|
||||
|
||||
// Define color & title for the status selected
|
||||
switch (deviceStatus) {
|
||||
case 'all': tableTitle = getString('Device_Shortcut_AllDevices'); color = 'aqua'; break;
|
||||
case 'connected': tableTitle = getString('Device_Shortcut_Connected'); color = 'green'; break;
|
||||
case 'favorites': tableTitle = getString('Device_Shortcut_Favorites'); color = 'yellow'; break;
|
||||
case 'new': tableTitle = getString('Device_Shortcut_NewDevices'); color = 'yellow'; break;
|
||||
case 'down': tableTitle = getString('Device_Shortcut_DownAlerts'); color = 'red'; break;
|
||||
case 'archived': tableTitle = getString('Device_Shortcut_Archived'); color = 'gray'; break;
|
||||
default: tableTitle = getString('Device_Shortcut_Devices'); color = 'gray'; break;
|
||||
}
|
||||
|
||||
// Set title and color
|
||||
$('#tableDevicesTitle')[0].className = 'box-title text-'+ color;
|
||||
$('#tableDevicesBox')[0].className = 'box box-'+ color;
|
||||
$('#tableDevicesTitle').html (tableTitle);
|
||||
|
||||
|
||||
function initializeDatatable () {
|
||||
for(i = 0; i < tableColumnOrder.length; i++)
|
||||
{
|
||||
// hide this column if not in the tableColumnVisible variable (we need to keep the MAC address (index 11) for functionality reasons)
|
||||
@@ -324,143 +389,203 @@ function initializeDatatable () {
|
||||
tableColumnHide.push(mapIndx(tableColumnOrder[i]));
|
||||
}
|
||||
}
|
||||
|
||||
var table=
|
||||
$('#tableDevices').DataTable({
|
||||
'paging' : true,
|
||||
'lengthChange' : true,
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, '<?= lang('Device_Tablelenght_all');?>']],
|
||||
'searching' : true,
|
||||
|
||||
'ordering' : true,
|
||||
'info' : true,
|
||||
'autoWidth' : false,
|
||||
|
||||
// Parameters
|
||||
'pageLength' : tableRows,
|
||||
'order' : tableOrder,
|
||||
// 'order' : [[3,'desc'], [0,'asc']],
|
||||
|
||||
'columnDefs' : [
|
||||
{visible: false, targets: tableColumnHide },
|
||||
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15)] },
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||
{width: '30px', targets: [mapIndx(10), mapIndx(13)] },
|
||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||
|
||||
// Device Name
|
||||
{targets: [mapIndx(0)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Connected Devices
|
||||
{targets: [mapIndx(15)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Icon
|
||||
{targets: [mapIndx(3)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<i class="fa fa-'+cellData+' " style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Full MAC
|
||||
{targets: [mapIndx(11)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// IP address
|
||||
{targets: [mapIndx(12)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeIp">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Favorite
|
||||
{targets: [mapIndx(4)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Dates
|
||||
{targets: [mapIndx(6), mapIndx(7)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html (translateHTMLcodes (cellData));
|
||||
} },
|
||||
|
||||
// Random MAC
|
||||
{targets: [mapIndx(9)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Status color
|
||||
{targets: [mapIndx(10)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
switch (cellData) {
|
||||
case 'Down': color='red'; break;
|
||||
case 'New': color='yellow'; break;
|
||||
case 'On-line': color='green'; break;
|
||||
case 'Off-line': color='gray text-white'; break;
|
||||
case 'Archived': color='gray text-white'; break;
|
||||
default: color='aqua'; break;
|
||||
};
|
||||
|
||||
$(td).html ('<a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="badge bg-'+ color +'">'+ cellData.replace('-', '') +'</a>');
|
||||
} },
|
||||
],
|
||||
$.get('api/table_devices.json', function(result) {
|
||||
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table> <td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td> </table>',
|
||||
emptyTable: 'No data',
|
||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
||||
"paginate": {
|
||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
||||
},
|
||||
"info": "<?= lang('Device_Table_info');?>",
|
||||
// Filter the data based on deviceStatus
|
||||
var filteredData = filterDataByStatus(result.data, deviceStatus);
|
||||
|
||||
// Convert JSON data into the desired format
|
||||
var dataArray = {
|
||||
data: filteredData.map(function(item) {
|
||||
var originalRow = [
|
||||
item.dev_Name || "",
|
||||
item.dev_Owner || "",
|
||||
item.dev_DeviceType || "",
|
||||
item.dev_Icon || "",
|
||||
item.dev_Favorite || "",
|
||||
item.dev_Group || "",
|
||||
// ---
|
||||
item.dev_FirstConnection || "",
|
||||
item.dev_LastConnection || "",
|
||||
item.dev_LastIP || "",
|
||||
(["2", "6", "A", "E", "a", "e"].includes(item.dev_MAC[1]) ? 1 : 0) || "", // Check if randomized MAC
|
||||
getDeviceStatus(item) || "",
|
||||
item.dev_MAC || "", // hidden
|
||||
formatIPlong(item.dev_LastIP) || "", // IP orderable
|
||||
item.rowid || "",
|
||||
item.dev_Network_Node_MAC_ADDR || "",
|
||||
item.connected_devices || 0,
|
||||
item.dev_Location || "",
|
||||
item.dev_Vendor || "",
|
||||
item.dev_Network_Node_port || 0
|
||||
];
|
||||
|
||||
var newRow = [];
|
||||
|
||||
// reorder data based on user-defined columns order
|
||||
for (index = 0; index < tableColumnOrder.length; index++) {
|
||||
newRow.push(originalRow[tableColumnOrder[index]]);
|
||||
}
|
||||
|
||||
return newRow;
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// TODO displayed columns
|
||||
|
||||
|
||||
// Check if the DataTable already exists
|
||||
if ($.fn.dataTable.isDataTable('#tableDevices')) {
|
||||
// The DataTable exists, so destroy it
|
||||
var table = $('#tableDevices').DataTable();
|
||||
table.clear().destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// Save cookie Rows displayed, and Parameters rows & order
|
||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parTableRows, len);
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'order.dt', function () {
|
||||
setParameter (parTableOrder, JSON.stringify (table.order()) );
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
var table=
|
||||
$('#tableDevices').DataTable({
|
||||
'data' : dataArray["data"],
|
||||
'paging' : true,
|
||||
'lengthChange' : true,
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
||||
'searching' : true,
|
||||
|
||||
$('#tableDevices').on( 'search.dt', function () {
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
'ordering' : true,
|
||||
'info' : true,
|
||||
'autoWidth' : false,
|
||||
|
||||
// Parameters
|
||||
'pageLength' : tableRows,
|
||||
'order' : tableOrder,
|
||||
|
||||
'columnDefs' : [
|
||||
{visible: false, targets: tableColumnHide },
|
||||
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15)] },
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||
{width: '30px', targets: [mapIndx(10), mapIndx(13)] },
|
||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||
|
||||
// Device Name
|
||||
{targets: [mapIndx(0)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
|
||||
// console.log(cellData)
|
||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Connected Devices
|
||||
{targets: [mapIndx(15)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Icon
|
||||
{targets: [mapIndx(3)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<i class="fa fa-'+cellData+' " style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Full MAC
|
||||
{targets: [mapIndx(11)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// IP address
|
||||
{targets: [mapIndx(12)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeIp">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Favorite
|
||||
{targets: [mapIndx(4)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Dates
|
||||
{targets: [mapIndx(6), mapIndx(7)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html (translateHTMLcodes (cellData));
|
||||
} },
|
||||
|
||||
// Random MAC
|
||||
{targets: [mapIndx(9)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
console.log(cellData)
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Status color
|
||||
{targets: [mapIndx(10)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
|
||||
// console.log(cellData)
|
||||
switch (cellData) {
|
||||
case 'Down': color='red'; break;
|
||||
case 'New': color='yellow'; break;
|
||||
case 'On-line': color='green'; break;
|
||||
case 'Off-line': color='gray text-white'; break;
|
||||
case 'Archived': color='gray text-white'; break;
|
||||
default: color='aqua'; break;
|
||||
};
|
||||
|
||||
$(td).html ('<a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="badge bg-'+ color +'">'+ cellData.replace('-', '') +'</a>');
|
||||
} },
|
||||
],
|
||||
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table> <td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td> </table>',
|
||||
emptyTable: 'No data',
|
||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
||||
"paginate": {
|
||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
||||
},
|
||||
"info": "<?= lang('Device_Table_info');?>",
|
||||
}
|
||||
});
|
||||
|
||||
// Save cookie Rows displayed, and Parameters rows & order
|
||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parTableRows, len);
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'order.dt', function () {
|
||||
setParameter (parTableOrder, JSON.stringify (table.order()) );
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'search.dt', function () {
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -513,37 +638,7 @@ function getDevicesTotals () {
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDeviceColumns () {
|
||||
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDevicesList (status) {
|
||||
// Save status selected
|
||||
deviceStatus = status;
|
||||
|
||||
// Define color & title for the status selected
|
||||
switch (deviceStatus) {
|
||||
case 'all': tableTitle = '<?= lang('Device_Shortcut_AllDevices');?>'; color = 'aqua'; break;
|
||||
case 'connected': tableTitle = '<?= lang('Device_Shortcut_Connected');?>'; color = 'green'; break;
|
||||
case 'favorites': tableTitle = '<?= lang('Device_Shortcut_Favorites');?>'; color = 'yellow'; break;
|
||||
case 'new': tableTitle = '<?= lang('Device_Shortcut_NewDevices');?>'; color = 'yellow'; break;
|
||||
case 'down': tableTitle = '<?= lang('Device_Shortcut_DownAlerts');?>'; color = 'red'; break;
|
||||
case 'archived': tableTitle = '<?= lang('Device_Shortcut_Archived');?>'; color = 'gray'; break;
|
||||
default: tableTitle = '<?= lang('Device_Shortcut_Devices');?>'; color = 'gray'; break;
|
||||
}
|
||||
|
||||
// Set title and color
|
||||
$('#tableDevicesTitle')[0].className = 'box-title text-'+ color;
|
||||
$('#tableDevicesBox')[0].className = 'box box-'+ color;
|
||||
$('#tableDevicesTitle').html (tableTitle);
|
||||
|
||||
// Define new datasource URL and reload
|
||||
$('#tableDevices').DataTable().ajax.url(
|
||||
'php/server/devices.php?action=getDevicesList&status=' + deviceStatus).load();
|
||||
};
|
||||
|
||||
function handleLoadingDialog()
|
||||
{
|
||||
$.get('api/app_state.json?nocache=' + Date.now(), function(appState) {
|
||||
|
||||
@@ -304,6 +304,32 @@ function showMessage (textMessage="") {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// String utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
function jsonSyntaxHighlight(json) {
|
||||
if (typeof json != 'string') {
|
||||
json = JSON.stringify(json, undefined, 2);
|
||||
}
|
||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||
var cls = 'number';
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
cls = 'key';
|
||||
} else {
|
||||
cls = 'string';
|
||||
}
|
||||
} else if (/true|false/.test(match)) {
|
||||
cls = 'boolean';
|
||||
} else if (/null/.test(match)) {
|
||||
cls = 'null';
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + '</span>';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// General utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -487,7 +513,21 @@ function getNameByMacAddress(macAddress) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// A function used to make the IP address orderable
|
||||
function formatIPlong(ipAddress) {
|
||||
const parts = ipAddress.split('.');
|
||||
if (parts.length !== 4) {
|
||||
throw new Error('Invalid IP address format');
|
||||
}
|
||||
return (parseInt(parts[0]) << 24) |
|
||||
(parseInt(parts[1]) << 16) |
|
||||
(parseInt(parts[2]) << 8) |
|
||||
parseInt(parts[3]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// A function to get a device property using the mac address as key and DB column nakme as parameter
|
||||
// for the value to be returned
|
||||
function getDeviceDataByMacAddress(macAddress, dbColumn) {
|
||||
|
||||
const sessionDataKey = 'devicesListAll_JSON';
|
||||
@@ -534,6 +574,15 @@ function isEmpty(value)
|
||||
return emptyArr.includes(value)
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Generate a GUID
|
||||
function getGuid() {
|
||||
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Loading Spinner overlay
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
109
front/js/settings_utils.js
Executable file
109
front/js/settings_utils.js
Executable file
@@ -0,0 +1,109 @@
|
||||
// -------------------------------------------------------------------
|
||||
// Get all plugin prefixes of a given type
|
||||
function getPluginsByType(pluginsData, pluginType, onlyEnabled)
|
||||
{
|
||||
|
||||
var result = []
|
||||
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if(plug.plugin_type == pluginType)
|
||||
{
|
||||
// collect all, or if only enabled, check if NOT disabled
|
||||
if (onlyEnabled == false || (onlyEnabled && getSetting(plug.unique_prefix + '_RUN') != 'disabled')) {
|
||||
result.push(plug.unique_prefix)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get plugin type base on prefix
|
||||
function getPluginType(pluginsData, prefix)
|
||||
{
|
||||
var result = "core"
|
||||
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if (plug.unique_prefix == prefix ) {
|
||||
id = plug.plugin_type;
|
||||
|
||||
// console.log(id)
|
||||
result = plug.plugin_type;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Generate plugin HTML card based on prefixes in an array
|
||||
function pluginCards(prefixesOfEnabledPlugins, includeSettings)
|
||||
{
|
||||
html = ""
|
||||
|
||||
prefixesOfEnabledPlugins.forEach((prefix) => {
|
||||
|
||||
includeSettings_html = ''
|
||||
|
||||
includeSettings.forEach((set) => {
|
||||
|
||||
includeSettings_html += `
|
||||
<a href="#${prefix + '_' + set}" onclick="toggleAllSettings()">
|
||||
<div class="overview-setting-value pointer" title="${prefix + '_' + set}">
|
||||
<code>${getSetting(prefix + '_' + set)}</code>
|
||||
</div>
|
||||
</a>
|
||||
`
|
||||
|
||||
});
|
||||
|
||||
html += `
|
||||
|
||||
<div class="col-sm-4 ">
|
||||
<div class="small-box bg-green " >
|
||||
<div class="inner ">
|
||||
<h5 class="card-title">
|
||||
${getString(prefix+"_display_name")}
|
||||
</h5>
|
||||
${includeSettings_html}
|
||||
</div>
|
||||
<div class="icon"> ${getString(prefix+"_icon")} </div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Checks if all schedules are the same
|
||||
function schedulesAreSynchronized(prefixesOfEnabledPlugins, pluginsData)
|
||||
{
|
||||
plug_schedules = []
|
||||
|
||||
prefixesOfEnabledPlugins.forEach((prefix) => {
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if (plug.unique_prefix == prefix) {
|
||||
|
||||
plug_schedules.push(getSetting(prefix+"_RUN_SCHD").replace(/\s/g, "")) // replace all white characters to compare them easier
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Check if all plug_schedules are the same
|
||||
if (plug_schedules.length > 0) {
|
||||
const firstSchedule = plug_schedules[0];
|
||||
return plug_schedules.every((schedule) => schedule === firstSchedule);
|
||||
}
|
||||
|
||||
return true; // Return true if no schedules are found
|
||||
}
|
||||
@@ -395,7 +395,7 @@ $db->close();
|
||||
<!-- ---------------------------Logging-------------------------------------------- -->
|
||||
<div class="tab-pane" id="tab_Logging">
|
||||
<div class="db_info_table">
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_log" class="logs" cols="70" rows="10" wrap='off' readonly >
|
||||
<?php
|
||||
@@ -420,8 +420,8 @@ $db->close();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area">
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_front_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert_front.log" ); ?>
|
||||
</textarea>
|
||||
@@ -437,7 +437,7 @@ $db->close();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_php_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert.php_errors.log" ); ?>
|
||||
</textarea>
|
||||
@@ -452,45 +452,19 @@ $db->close();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="log-area">
|
||||
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_pholus_lastrun_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert_pholus_lastrun.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file">pialert_pholus_lastrun.log<div class="logs-size"><?php echo number_format((filesize("./log/pialert_pholus_lastrun.log") / 1000000),2,",",".") . ' MB';?>
|
||||
<span class="span-padding"><a href="./log/pialert_pholus_lastrun.log"><i class="fa fa-download"></i> </a></span>
|
||||
</div></div>
|
||||
<div class="log-purge">
|
||||
<button class="btn btn-primary" onclick="logManage('pialert_pholus_lastrun.log','cleanLog')"><?= lang('Gen_Purge');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary ">
|
||||
<div class="row logs-row">
|
||||
<textarea id="IP_changes_log" class="logs logs-small" cols="70" rows="10" readonly><?php echo file_get_contents( "./log/IP_changes.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file">IP_changes.log<div class="logs-size"><?php echo number_format((filesize("./log/IP_changes.log") / 1000000),2,",",".") . ' MB';?>
|
||||
<span class="span-padding"><a href="./log/IP_changes.log"><i class="fa fa-download"></i> </a></span>
|
||||
</div></div>
|
||||
<div class="log-purge">
|
||||
<button class="btn btn-primary" onclick="logManage('IP_changes.log','cleanLog')"><?= lang('Gen_Purge');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
<textarea id="nginx_error_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "/var/log/nginx/error.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file" title="/var/log/nginx/error.log">nginx/error.log</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="stdout_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stdout.log" ); ?>
|
||||
</textarea>
|
||||
@@ -507,7 +481,7 @@ $db->close();
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="stderr_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stderr.log" ); ?>
|
||||
</textarea>
|
||||
@@ -786,7 +760,7 @@ function performLogManage() {
|
||||
showModalOk ('Result', data );
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
function scrollDown()
|
||||
|
||||
@@ -551,7 +551,8 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getHierarchy()
|
||||
{
|
||||
{
|
||||
|
||||
for(i in deviceListGlobal)
|
||||
{
|
||||
if(deviceListGlobal[i].mac == 'Internet')
|
||||
@@ -596,95 +597,114 @@
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handle network node click - select correct tab in teh bottom table
|
||||
function handleNodeClick(event)
|
||||
{
|
||||
|
||||
console.log(event.target.offsetParent)
|
||||
|
||||
const targetTabMAC = $(event.target.offsetParent).attr("data-mytreemacmain");
|
||||
console.log(event.target.offsetParent.offsetParent)
|
||||
|
||||
const targetTabMAC = $(event.target.offsetParent.offsetParent).attr("data-mytreemacmain");
|
||||
|
||||
var targetTab = $(`a[data-mytabmac="${targetTabMAC}"]`);
|
||||
|
||||
// Simulate a click event on the target tab
|
||||
targetTab.click();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
var myTree;
|
||||
var treeAreaHeight = 800;
|
||||
var emSize;
|
||||
var nodeHeight;
|
||||
var sizeCoefficient = 1
|
||||
|
||||
function initTree(myHierarchy)
|
||||
{
|
||||
{
|
||||
// calculate the font size of the leaf nodes to fit everything into the tree area
|
||||
leafNodesCount == 0 ? 1 : leafNodesCount;
|
||||
emSize = ((treeAreaHeight/(25*leafNodesCount)).toFixed(2));
|
||||
emSize = emSize > 1 ? 1 : emSize;
|
||||
|
||||
emSize = ((treeAreaHeight/(25*leafNodesCount)).toFixed(2));
|
||||
emSize = emSize > 1 ? 1 : emSize;
|
||||
|
||||
// nodeHeight = ((emSize*100*0.30).toFixed(0))
|
||||
nodeHeight = ((emSize*100*0.30).toFixed(0))
|
||||
|
||||
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${$('.content-header').width()}px`)
|
||||
|
||||
console.log('here')
|
||||
|
||||
myTree = Treeviz.create({
|
||||
htmlId: "networkTree",
|
||||
|
||||
renderNode: nodeData => {
|
||||
renderNode: nodeData => {
|
||||
var fontSize = "font-size:"+emSize+"em;";
|
||||
|
||||
(!emptyArr.includes(nodeData.data.port )) ? port = nodeData.data.port : port = "";
|
||||
|
||||
(port == "" || port == 0 ) ? portBckgIcon = `<i class="fa fa-wifi"></i>` : portBckgIcon = `<i class="fa fa-ethernet"></i>`;
|
||||
|
||||
// Build HTML for individual nodes in the network diagram
|
||||
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ? "<div class='netIcon ' ><i class='fa fa-"+nodeData.data.icon +"'></i></div>" : "";
|
||||
devicePort = `<div class='netPort ' style="width:${emSize*2.7}em;height:${emSize*2.7}em" >${port}</div> <div class="portBckgIcon" style="margin-left:-${emSize*2.5}em;">${portBckgIcon}</div>`;
|
||||
collapseExpandIcon = nodeData.data.hiddenChildren ? "square-plus" :"square-minus";
|
||||
collapseExpandHtml = (nodeData.data.hasChildren) ? "<div class='netCollapse' style='font-size:"+emSize*2.5+"em;' data-mytreepath='"+nodeData.data.path+"' data-mytreemac='"+nodeData.data.mac+"'><i class='fa fa-"+ collapseExpandIcon +" pointer'></i></div>" : "";
|
||||
statusCss = " netStatus-" + nodeData.data.status;
|
||||
// Build HTML for individual nodes in the network diagram
|
||||
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ?
|
||||
`<div class="netIcon">
|
||||
<i class="fa fa-${nodeData.data.icon}"></i>
|
||||
</div>` : "";
|
||||
devicePort = `<div class="netPort"
|
||||
style="width:${emSize*sizeCoefficient}em;height:${emSize*sizeCoefficient}em">
|
||||
${port}</div>
|
||||
<div class="portBckgIcon"
|
||||
style="margin-left:-${emSize*sizeCoefficient}em;">
|
||||
${portBckgIcon}
|
||||
</div>`;
|
||||
collapseExpandIcon = nodeData.data.hiddenChildren ?
|
||||
"square-plus" : "square-minus";
|
||||
|
||||
// generate +/- icon if node has children nodes
|
||||
collapseExpandHtml = nodeData.data.hasChildren ?
|
||||
`<div class="netCollapse"
|
||||
style="font-size:${emSize*sizeCoefficient}em;top:${1/2*emSize*sizeCoefficient}em"
|
||||
data-mytreepath="${nodeData.data.path}"
|
||||
data-mytreemac="${nodeData.data.mac}">
|
||||
<i class="fa fa-${collapseExpandIcon} pointer"></i>
|
||||
</div>` : "";
|
||||
|
||||
selectedNodeMac = $(".nav-tabs-custom .active a").attr('data-mytabmac')
|
||||
|
||||
highlightedCss = nodeData.data.mac == selectedNodeMac ? " highlightedNode" : "";
|
||||
highlightedCss = nodeData.data.mac == selectedNodeMac ?
|
||||
" highlightedNode" : "";
|
||||
|
||||
return result = `<div class='box ${(nodeData.data.hasChildren)? "pointer":""} ${statusCss} ${highlightedCss}'
|
||||
data-mytreemacmain='${nodeData.data.mac}'
|
||||
style='height:${nodeData.settings.nodeHeight}px;${fontSize}
|
||||
// css indicating online/offline status
|
||||
statusCss = ` netStatus-${nodeData.data.status}`;
|
||||
|
||||
return result = `<div class="box ${nodeData.data.hasChildren ? "pointer":""} ${statusCss} ${highlightedCss}"
|
||||
data-mytreemacmain="${nodeData.data.mac}"
|
||||
style="height:${nodeData.settings.nodeHeight}px;${fontSize}"
|
||||
>
|
||||
<div class='netNodeText '>\
|
||||
<strong>${devicePort} ${deviceIcon}
|
||||
<span class='spanNetworkTree anonymizeDev'>${nodeData.data.name}</span>\
|
||||
</strong>
|
||||
${collapseExpandHtml}
|
||||
</div></div>`;
|
||||
},
|
||||
<div class="netNodeText">
|
||||
<strong>${devicePort} ${deviceIcon}
|
||||
<span class="spanNetworkTree anonymizeDev">${nodeData.data.name}</span>
|
||||
</strong>
|
||||
${collapseExpandHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
onNodeClick: nodeData => {
|
||||
console.log(this)
|
||||
},
|
||||
onNodeClick: nodeData => {
|
||||
console.log(this)
|
||||
},
|
||||
mainAxisNodeSpacing: 'auto',
|
||||
// mainAxisNodeSpacing: 3,
|
||||
secondaryAxisNodeSpacing: 0.3,
|
||||
nodeHeight: nodeHeight.toString(),
|
||||
nodeHeight: nodeHeight.toString(),
|
||||
marginTop: '5',
|
||||
hasZoom: false,
|
||||
hasPan: false,
|
||||
// marginLeft: '15',
|
||||
idKey: "id",
|
||||
hasFlatData: false,
|
||||
hasFlatData: false,
|
||||
linkWidth: (nodeData) => 3,
|
||||
linkColor: (nodeData) => "#ffcc80",
|
||||
onNodeClick: (nodeData) => handleNodeClick(nodeData),
|
||||
relationnalField: "children",
|
||||
relationnalField: "children",
|
||||
});
|
||||
|
||||
console.log('vvvv')
|
||||
console.log(myHierarchy)
|
||||
console.log('^^^^^^^')
|
||||
|
||||
myTree.refresh(myHierarchy);
|
||||
|
||||
myTree.refresh(myHierarchy);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -646,12 +646,14 @@ function getDevicesList() {
|
||||
$tableData = array();
|
||||
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
|
||||
$defaultOrder = array ($row['dev_Name'],
|
||||
$defaultOrder = array (
|
||||
$row['dev_Name'],
|
||||
$row['dev_Owner'],
|
||||
handleNull($row['dev_DeviceType']),
|
||||
handleNull($row['dev_Icon'], "laptop"),
|
||||
$row['dev_Favorite'],
|
||||
$row['dev_Group'],
|
||||
// ----
|
||||
formatDate ($row['dev_FirstConnection']),
|
||||
formatDate ($row['dev_LastConnection']),
|
||||
$row['dev_LastIP'],
|
||||
@@ -857,8 +859,6 @@ function getDevices() {
|
||||
function getDeviceTypes() {
|
||||
global $db;
|
||||
|
||||
$networkTypes = getNetworkTypes();
|
||||
|
||||
// SQL
|
||||
$sql = 'SELECT DISTINCT 9 as dev_Order, dev_DeviceType
|
||||
FROM Devices
|
||||
|
||||
@@ -13,28 +13,47 @@ require dirname(__FILE__).'/../templates/skinUI.php';
|
||||
|
||||
$FUNCTION = [];
|
||||
$SETTINGS = [];
|
||||
$ACTION = "";
|
||||
|
||||
// init request params
|
||||
if(array_key_exists('function', $_REQUEST) != FALSE)
|
||||
{
|
||||
$FUNCTION = $_REQUEST['function'];
|
||||
}
|
||||
|
||||
if(array_key_exists('settings', $_REQUEST) != FALSE)
|
||||
{
|
||||
$SETTINGS = $_REQUEST['settings'];
|
||||
}
|
||||
|
||||
|
||||
// call functions based on requested params
|
||||
if ($FUNCTION == 'savesettings')
|
||||
{
|
||||
saveSettings();
|
||||
}
|
||||
elseif ($FUNCTION == 'cleanLog')
|
||||
{
|
||||
cleanLog($SETTINGS);
|
||||
switch ($FUNCTION) {
|
||||
case 'savesettings':
|
||||
|
||||
saveSettings();
|
||||
break;
|
||||
|
||||
case 'cleanLog':
|
||||
|
||||
cleanLog($SETTINGS);
|
||||
break;
|
||||
|
||||
case 'addToExecutionQueue':
|
||||
|
||||
if(array_key_exists('action', $_REQUEST) != FALSE)
|
||||
{
|
||||
$ACTION = $_REQUEST['action'];
|
||||
}
|
||||
|
||||
addToExecutionQueue($ACTION);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Handle any other cases or errors if needed
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Formatting data functions
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -195,6 +214,25 @@ function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFil
|
||||
|
||||
}
|
||||
|
||||
// Adds an action to perform into the execution_queue.log file
|
||||
function addToExecutionQueue($action)
|
||||
{
|
||||
global $logFolderPath, $timestamp;
|
||||
|
||||
$logFile = 'execution_queue.log';
|
||||
$fullPath = $logFolderPath . $logFile;
|
||||
|
||||
// Open the file or skip if it can't be opened
|
||||
if ($file = fopen($fullPath, 'a')) {
|
||||
fwrite($file, "[" . $timestamp . "]|" . $action . PHP_EOL);
|
||||
fclose($file);
|
||||
displayMessage('Action "'.$action.'" added to the execution queue.', false, true, true, true);
|
||||
} else {
|
||||
displayMessage('Log file not found or couldn\'t be created.', false, true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
function cleanLog($logFile)
|
||||
{
|
||||
@@ -328,9 +366,16 @@ function saveSettings()
|
||||
$txt = $txt."#-------------------IMPORTANT INFO-------------------#\n";
|
||||
|
||||
// open new file and write the new configuration
|
||||
$newConfig = fopen($fullConfPath, "w") or die("Unable to open file!");
|
||||
fwrite($newConfig, $txt);
|
||||
fclose($newConfig);
|
||||
// Create a temporary file
|
||||
$tempConfPath = $fullConfPath . ".tmp";
|
||||
|
||||
// Write your changes to the temporary file
|
||||
$tempConfig = fopen($tempConfPath, "w") or die("Unable to open file!");
|
||||
fwrite($tempConfig, $txt);
|
||||
fclose($tempConfig);
|
||||
|
||||
// Replace the original file with the temporary file
|
||||
rename($tempConfPath, $fullConfPath);
|
||||
|
||||
displayMessage("<br/>Settings saved to the <code>pialert.conf</code> file.<br/><br/>A time-stamped backup of the previous file created. <br/><br/> Reloading...<br/>",
|
||||
FALSE, TRUE, TRUE, TRUE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -72,7 +72,7 @@
|
||||
"Device_TableHead_FirstSession" : "First Session",
|
||||
"Device_TableHead_LastSession" : "Last Session",
|
||||
"Device_TableHead_LastIP" : "Last IP",
|
||||
"Device_TableHead_MAC" : "MAC",
|
||||
"Device_TableHead_MAC" : "Random MAC",
|
||||
"Device_TableHead_MAC_full" : "Full MAC",
|
||||
"Device_TableHead_LastIPOrder" : "Last IP Order",
|
||||
"Device_TableHead_Status" : "Status",
|
||||
@@ -410,6 +410,7 @@
|
||||
"Network_Parent" : "Parent network device",
|
||||
"Network_Cant_Assign" : "Can't assign the root Internet node as a child leaf node.",
|
||||
"Network_NoAssignedDevices" : "This network node does not have any assigned devices (leaf nodes). Assign one from bellow or go to the <b><i class=\"fa fa-info-circle\"></i> Details</b> tab of any device in <a href=\"devices.php\"><b> <i class=\"fa fa-laptop\"></i> Devices</b></a>, and assign it to a network <b><i class=\"fa fa-server\"></i> Node (MAC)</b> and <b><i class=\"fa fa-ethernet\"></i> Port</b> there.",
|
||||
"Network_Root_Unconfigurable": "Unconfigurable root",
|
||||
"HelpFAQ_Title" : "Help / FAQ",
|
||||
"HelpFAQ_Cat_General" : "General",
|
||||
"HelpFAQ_Cat_Detail" : "Details",
|
||||
@@ -451,7 +452,7 @@
|
||||
"run_event_tooltip" : "Enable the setting and save your changes at first before you run it.",
|
||||
"run_event_icon" : "fa-play",
|
||||
"general_event_title" : "Executing an ad-hoc event",
|
||||
"general_event_description" : " The event you nove triggered might take a while until background processes finish. The execution ended once you see <code>finished</code> below. Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you didn not get the expected result. <br/> <br/> Status: ",
|
||||
"general_event_description" : "The event you have triggered might take a while until background processes finish. The execution ended once the below execution queue empties (Check the <a href='/maintenance.php#tab_Logging'>error log</a> if you encounter issues). <br/> <br/> Execution queue:",
|
||||
"Plugins_Unprocessed_Events" : "Unprocessed Events",
|
||||
"Plugins_Objects" : "Plugin Objects",
|
||||
"Plugins_DeleteAll" : "Delete all (filters are ignored)",
|
||||
@@ -459,13 +460,31 @@
|
||||
"Plugins_Filters_Mac" : "Mac Filter",
|
||||
"Plugins_Out_of" : "out of",
|
||||
"Plugins_no_control" : "No form control was found to render this value.",
|
||||
"settings_enabled" : "Enabled settings",
|
||||
"settings_enabled_icon" : "fa-solid fa-toggle-on",
|
||||
"settings_core_icon" : "fa-solid fa-gem",
|
||||
"settings_device_scanners_icon" : "fa-solid fa-magnifying-glass-plus",
|
||||
"settings_other_scanners_icon" : "fa-solid fa-recycle",
|
||||
"settings_system_icon" : "fa-solid fa-gear",
|
||||
"settings_publishers_icon" : "fa-solid fa-comment-dots",
|
||||
"Settings_Metadata_Toggle" : "Show/hide metadata for the given setting.",
|
||||
"settings_missing" : "Not all settings loaded, refresh the page! This is probably caused by a high load on the database or app startup sequence.",
|
||||
"settings_missing_block" : "You can not save your settings without specifying all setting keys. Refresh the page. This is probably caused by a high load on the database.",
|
||||
"settings_old" : "Importing settings and re-initializing...",
|
||||
"settings_saved" : "<br/>Settings saved to the <code>pialert.conf</code> file.<br/><br/>A time-stamped backup of the previous file created. <br/><br/> Reloading...<br/>",
|
||||
"settings_imported" : "Last time settings were imported from the pialert.conf file:",
|
||||
"settings_saved" : "<br/>Settings saved to the <code>pialert.conf</code> file.<br/><br/>A time-stamped backup of the previous file created. <br/><br/> Reloading...<br/>",
|
||||
"settings_system_label" : "System",
|
||||
"settings_core_label" : "Core",
|
||||
"settings_imported_label" : "Settings imported",
|
||||
"settings_imported" : "Last time settings were imported from the pialert.conf file",
|
||||
"settings_other_scanners_label" : "Other scanners",
|
||||
"settings_other_scanners" : "Other, non-device scanner plugins that are currently enabled.",
|
||||
"settings_device_scanners_label" : "Device scanners",
|
||||
"settings_device_scanners" : "Device scanners used to discover devices that write into the CurrentScan database table.",
|
||||
"settings_publishers_label" : "Publishers",
|
||||
"settings_publishers" : "Enabled notification gateways - publishers, that will send a notification depending on your settings.",
|
||||
"settings_expand_all" : "Expand all",
|
||||
"Settings_device_Scanners_desync": "⚠ Device scanner schedules are out-of-sync.",
|
||||
"Settings_device_Scanners_desync_popup": "Schedules of devices scanners (<code>*_RUN_SCHD</code>) are not the same. This will result into inconsistent device online/offline notifications. Unless this is intended, please use the same schedule for all enabled <b>🔍Device scanners</b>.",
|
||||
"Setting_Override" : "Override value",
|
||||
"Setting_Override_Description" : "Enabling this option will override an App supplied default value with the value specified above.",
|
||||
"General_display_name" : "General",
|
||||
@@ -478,7 +497,9 @@
|
||||
"ENABLE_PLUGINS_name" : "Enable Plugins",
|
||||
"ENABLE_PLUGINS_description" : "Enables the <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins\">plugins</a> functionality. Loading plugins requires more hardware resources so you might want to disable them on low-powered system.",
|
||||
"PLUGINS_KEEP_HIST_name" : "Plugins History",
|
||||
"PLUGINS_KEEP_HIST_description" : "How many entries of Plugins History scan results should be kept (per Plugin, not device specific).",
|
||||
"PLUGINS_KEEP_HIST_description" : "How many entries of Plugins History scan results should be kept (per Plugin, and not device specific).",
|
||||
"DBCLNP_NOTIFI_HIST_name" : "Notifications History",
|
||||
"DBCLNP_NOTIFI_HIST_description" : "How many historical entries of Notifications should be kept.",
|
||||
"PIALERT_WEB_PROTECTION_name" : "Enable login",
|
||||
"PIALERT_WEB_PROTECTION_description" : "When enabled a login dialog is displayed. Read below carefully if you get locked out of your instance.",
|
||||
"PIALERT_WEB_PASSWORD_name" : "Login password",
|
||||
@@ -490,7 +511,7 @@
|
||||
"HRS_TO_KEEP_NEWDEV_name" : "Keep new devices for",
|
||||
"HRS_TO_KEEP_NEWDEV_description" : "This is a maintenance setting. If enabled (<code>0</code> is disabled), devices marked as <b>New Device</b> will be deleted if their <b>First Session</b> time was older than the specified hours in this setting. Use this setting if you want to auto-delete <b>New Devices</b> after <code>X</code> hours.",
|
||||
"REPORT_DASHBOARD_URL_name" : "Pi.Alert URL",
|
||||
"REPORT_DASHBOARD_URL_description" : "This URL is used as the base for generating links in the emails. Enter full URL starting with <code>http://</code> including the port number (no trailig slash <code>/</code>).",
|
||||
"REPORT_DASHBOARD_URL_description" : "This URL is used as the base for generating links in HTML reports (e.g.: emails). Enter full URL starting with <code>http://</code> including the port number (no trailig slash <code>/</code>).",
|
||||
"DIG_GET_IP_ARG_name" : "Internet IP discovery",
|
||||
"DIG_GET_IP_ARG_description" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>.",
|
||||
"NETWORK_DEVICE_TYPES_name" : "Network device types",
|
||||
@@ -503,87 +524,9 @@
|
||||
"Email_icon" : "<i class=\"fa fa-at\"></i>",
|
||||
"REPORT_MAIL_name" : "Enable email",
|
||||
"REPORT_MAIL_description" : "If enabled an email is sent out with a list of changes you nove subscribed to. Please also fill out all remaining settings related to the SMTP setup below. If facing issues, set <code>LOG_LEVEL</code> to <code>debug</code> and check the <a href=\"/maintenance.php#tab_Logging\">error log</a>.",
|
||||
"SMTP_SERVER_name" : "SMTP server URL",
|
||||
"SMTP_SERVER_description" : "The SMTP server host URL. For example <code>smtp-relay.sendinblue.com</code>. To use Gmail as an SMTP server <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SMTP.md\">follow this guide</a>",
|
||||
"SMTP_PORT_name" : "SMTP server PORT",
|
||||
"SMTP_PORT_description" : "Port number used for the SMTP connection. Set to <code>0</code> if you do not want to use a port when connecting to the SMTP server.",
|
||||
"SMTP_SKIP_LOGIN_name" : "Skip authentication",
|
||||
"SMTP_SKIP_LOGIN_description" : "Do not use authentication when connecting to the SMTP server.",
|
||||
"SMTP_USER_name" : "SMTP user",
|
||||
"SMTP_USER_description" : "The user name used to login into the SMTP server (sometimes a full email address).",
|
||||
"SMTP_PASS_name" : "SMTP password",
|
||||
"SMTP_PASS_description" : "The SMTP server password. ",
|
||||
"SMTP_SKIP_TLS_name" : "Do not use TLS",
|
||||
"SMTP_SKIP_TLS_description" : "Disable TLS when connecting to your SMTP server.",
|
||||
"SMTP_FORCE_SSL_name" : "Force SSL",
|
||||
"SMTP_FORCE_SSL_description" : "Force SSL when connecting to your SMTP server.",
|
||||
"SYSTEM_TITLE" : "System Information",
|
||||
"REPORT_TO_name" : "Send email to",
|
||||
"REPORT_TO_description" : "Email address to which the notification will be send to.",
|
||||
"REPORT_FROM_name" : "Email subject",
|
||||
"REPORT_FROM_description" : "Notification email subject line. Some SMTP servers need this to be an email.",
|
||||
"Webhooks_display_name" : "Webhooks",
|
||||
"Webhooks_icon" : "<i class=\"fa fa-circle-nodes\"></i>",
|
||||
"REPORT_WEBHOOK_name" : "Enable Webhooks",
|
||||
"REPORT_WEBHOOK_description" : "Enable webhooks for notifications. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or <a href=\"https://n8n.io/\" target=\"_blank\">n8n</a> to name a few. Check out this simple <a href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md\" target=\"_blank\">n8n guide here</a> to get started. If enabled, configure related settings below.",
|
||||
"WEBHOOK_URL_name" : "Target URL",
|
||||
"WEBHOOK_URL_description" : "Target URL starting with <code>http://</code> or <code>https://</code>.",
|
||||
"WEBHOOK_PAYLOAD_name" : "Payload type",
|
||||
"WEBHOOK_PAYLOAD_description" : "The Webhook payload data format for the <code>body</code> > <code>attachments</code> > <code>text</code> attribute in the payload json. See an example of the payload <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json\">here</a>. (e.g.: for discord use <code>text</code>)",
|
||||
"WEBHOOK_REQUEST_METHOD_name" : "Request method",
|
||||
"WEBHOOK_REQUEST_METHOD_description" : "The HTTP request method to be used for the webhook call.",
|
||||
"WEBHOOK_SIZE_name" : "Max payload size",
|
||||
"WEBHOOK_SIZE_description" : "The maximum size of the webhook payload as number of characters in the passed string. If above limit, it will be truncated and a <code>(text was truncated)</code> message is appended.",
|
||||
"WEBHOOK_SECRET_name": "HMAC Secret",
|
||||
"WEBHOOK_SECRET_description": "When set, use this secret to generate the SHA256-HMAC hex digest value of the request body, which will be passed as the <code>X-Webhook-Signature</code> header to the request. You can find more informations <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_SECRET.md\">here</a>.",
|
||||
"Apprise_display_name" : "Apprise",
|
||||
"Apprise_icon" : "<i class=\"fa fa-bullhorn\"></i>",
|
||||
"REPORT_APPRISE_name" : "Enable Apprise",
|
||||
"REPORT_APPRISE_description" : "Enable sending notifications via <a target=\"_blank\" href=\"https://hub.docker.com/r/caronc/apprise\">Apprise</a>.",
|
||||
"APPRISE_HOST_name" : "Apprise host URL",
|
||||
"APPRISE_HOST_description" : "Apprise host URL starting with <code>http://</code> or <code>https://</code>. (do not forget to include <code>/notify</code> at the end)",
|
||||
"APPRISE_URL_name" : "Apprise notification URL",
|
||||
"APPRISE_URL_description" : "Apprise notification target URL. For example for Telegram it would be <code>tgram://{bot_token}/{chat_id}</code>.",
|
||||
"APPRISE_SIZE_name" : "Max payload size",
|
||||
"APPRISE_SIZE_description" : "The maximum size of the apprise payload as number of characters in the passed string. If above limit, it will be truncated and a <code>(text was truncated)</code> message is appended.",
|
||||
"NTFY_display_name" : "NTFY",
|
||||
"NTFY_icon" : "<i class=\"fa fa-terminal\"></i>",
|
||||
"REPORT_NTFY_name" : "Enable NTFY",
|
||||
"REPORT_NTFY_description" : "Enable sending notifications via <a target=\"_blank\" href=\"https://ntfy.sh/\">NTFY</a>.",
|
||||
"NTFY_HOST_name" : "NTFY host URL",
|
||||
"NTFY_HOST_description" : "NTFY host URL starting with <code>http://</code> or <code>https://</code>. You can use the hosted instance on <a target=\"_blank\" href=\"https://ntfy.sh/\">https://ntfy.sh</a> by simply entering <code>https://ntfy.sh</code>.",
|
||||
"NTFY_TOPIC_name" : "NTFY topic",
|
||||
"NTFY_TOPIC_description" : "Your secret topic.",
|
||||
"NTFY_USER_name" : "NTFY user",
|
||||
"NTFY_USER_description" : "Enter user if you need (host) an instance with enabled authetication.",
|
||||
"NTFY_PASSWORD_name" : "NTFY password",
|
||||
"NTFY_PASSWORD_description" : "Enter password if you need (host) an instance with enabled authetication.",
|
||||
"PUSHSAFER_display_name" : "Pushsafer",
|
||||
"PUSHSAFER_icon" : "<i class=\"fa fa-bell\"></i>",
|
||||
"REPORT_PUSHSAFER_name" : "Enable Pushsafer",
|
||||
"REPORT_PUSHSAFER_description" : "Enable sending notifications via <a target=\"_blank\" href=\"https://www.pushsafer.com/\">Pushsafer</a>.",
|
||||
"PUSHSAFER_TOKEN_name" : "Pushsafer token",
|
||||
"PUSHSAFER_TOKEN_description" : "Your secret Pushsafer API key (token).",
|
||||
"APPRISE_PAYLOAD_name" : "Payload type",
|
||||
"APPRISE_PAYLOAD_description" : "Select the payoad type sent to Apprise. For example <code>html</code> works well with emails, <code>text</code> with chat apps, such as Telegram.",
|
||||
"MQTT_display_name" : "MQTT",
|
||||
"MQTT_icon" : "<i class=\"fa fa-square-rss\"></i>",
|
||||
"SYSTEM_TITLE" : "System Information",
|
||||
"REPORT_TITLE" : "Report",
|
||||
"REPORT_ERROR" : "The page you are looking for is temporarily unavailable, please try again after a few seconds",
|
||||
"REPORT_MQTT_name" : "Enable MQTT",
|
||||
"REPORT_MQTT_description" : "Enable sending notifications via <a target=\"_blank\" href=\"https://www.home-assistant.io/integrations/mqtt/\">MQTT</a> to your Home Assistance instance.",
|
||||
"MQTT_BROKER_name" : "MQTT broker URL",
|
||||
"MQTT_BROKER_description" : "MQTT host URL (do not include <code>http://</code> or <code>https://</code>).",
|
||||
"MQTT_PORT_name" : "MQTT broker port",
|
||||
"MQTT_PORT_description" : "Port number where the broker is listening. Usually <code>1883</code>.",
|
||||
"MQTT_USER_name" : "MQTT user",
|
||||
"MQTT_USER_description" : "User name used to login into your MQTT broker instance.",
|
||||
"MQTT_PASSWORD_name" : "MQTT password",
|
||||
"MQTT_PASSWORD_description" : "Password used to login into your MQTT broker instance.",
|
||||
"MQTT_QOS_name" : "MQTT Quality of Service",
|
||||
"MQTT_QOS_description" : "Quality of service setting for MQTT message sending. <code>0</code> - Low quality to <code>2</code> - High quality. The higher the quality the longer the delay.",
|
||||
"MQTT_DELAY_SEC_name" : "MQTT delay per device",
|
||||
"MQTT_DELAY_SEC_description" : "A little hack - delay adding to the queue in case the process is restarted and previous publish processes aborted (it takes ~<code>2</code>s to update a sensor config on the broker). Tested with <code>2</code>-<code>3</code> seconds of delay. This delay is only applied when devices are created (during the first notification loop). It doesn not affect subsequent scans or notifications.",
|
||||
"REPORT_ERROR" : "The page you are looking for is temporarily unavailable, please try again after a few seconds",
|
||||
"API_display_name" : "API",
|
||||
"API_icon" : "<i class=\"fa fa-arrow-down-up-across-line\"></i>",
|
||||
"API_CUSTOM_SQL_name" : "Custom endpoint",
|
||||
@@ -658,7 +601,11 @@
|
||||
"Systeminfo_System_System": "System:",
|
||||
"Systeminfo_System_Uname": "Uname:",
|
||||
"Systeminfo_System_Uptime": "Uptime:",
|
||||
"Systeminfo_USB_Devices" : "USB Devices",
|
||||
"Systeminfo_USB_Devices" : "USB Devices",
|
||||
"report_select_format": "Select Format:",
|
||||
"report_time": "Notification time:",
|
||||
"report_guid": "Notification guid:",
|
||||
"report_guid_missing": "Linked notification not found. The selected notification might have been deleted during maintenance as specified in the <code>DBCLNP_NOTIFI_HIST</code> setting. The latest notification is dispalyed instead. The missing notification has the following GUID:",
|
||||
"Donations_Title" : "Donations",
|
||||
"Donations_Text" : "Hey 👋! </br> Thanks for clicking on this menu item 😅 </br> </br> I'm trying to collect some donations to make you better software. Also, it would help me not to get burned out. Me burning out might mean end of support for this app. Any small (recurring or not) sponsorship makes me want ot put more effort into this app. I don't want to lock features (new plugins) behind paywalls 🔐. </br> Currently, I'm waking up 2h before work so I contribute to the app a bit. If I had some recurring income I could shorten my workweek and in the remaining time fully focus on PiAlert. You'd get more functionality, a more polished app and less bugs. </br> </br> Thanks for reading - I'm super grateful for any support ❤🙏 </br> </br> TL;DR: By supporting me you get: </br> </br> <ul><li>Regular updates to keep your data and family safe 🔄</li><li>Less bugs 🐛🔫</li><li>Better and more functionality➕</li><li>I don't get burned out 🔥🤯</li><li>Less rushed releases 💨</li><li>Better docs📚</li><li>Quicker and better support with issues 🆘</li><li>Less grumpy me 😄</li></ul> </br> 📧Email me to <a href='mailto:jokob@duck.com?subject=PiAlert'>jokob@duck.com</a> if you want to get in touch or if I should add other sponsorship platforms. </br>",
|
||||
"Donations_Platforms" : "Sponsor platforms",
|
||||
|
||||
@@ -14,32 +14,42 @@
|
||||
|
||||
### 🔌 Plugins & 📚 Docs
|
||||
|
||||
| Required | CurrentScan | Unique Prefix | Plugin Type | Link + Docs |
|
||||
|-------------|-------------|-----------------------|------------------------|----------------------------------------------------------|
|
||||
| | Yes | ARPSCAN | Script | 📚[arp_scan](/front/plugins/arp_scan/) |
|
||||
| | | CSVBCKP | Script | 📚[csv_backup](/front/plugins/csv_backup/) |
|
||||
| Yes* | | DBCLNP | Script | 📚[db_cleanup](/front/plugins/db_cleanup/) |
|
||||
| | | DDNS | Script | 📚[ddns_update](/front/plugins/ddns_update/) |
|
||||
| | Yes | DHCPLSS | Script | 📚[dhcp_leases](/front/plugins/dhcp_leases/) |
|
||||
| | | DHCPSRVS | Script | 📚[dhcp_servers](/front/plugins/dhcp_servers/) |
|
||||
| | Yes | INTRNT | Script | 📚[internet_ip](/front/plugins/internet_ip/) |
|
||||
| Yes | | NEWDEV | Template | 📚[newdev_template](/front/plugins/newdev_template/) |
|
||||
| | | NMAP | Script | 📚[nmap_scan](/front/plugins/nmap_scan/) |
|
||||
| | Yes | PIHOLE | External SQLite DB | 📚[pihole_scan](/front/plugins/pihole_scan/) |
|
||||
| | | SETPWD | Script | 📚[set_password](/front/plugins/set_password/) |
|
||||
| | | SNMPDSC | Script | 📚[snmp_discovery](/front/plugins/snmp_discovery/) |
|
||||
| | Yes* | UNDIS | Script | 📚[undiscoverables](/front/plugins/undiscoverables/) |
|
||||
| | Yes | UNFIMP | Script | 📚[unifi_import](/front/plugins/unifi_import/) |
|
||||
| | | VNDRPDT | Script | 📚[vendor_update](/front/plugins/vendor_update/) |
|
||||
| | | WEBMON | Script | 📚[website_monitor](/front/plugins/website_monitor/) |
|
||||
| N/A | | N/A | SQL query | N/A, but the External SQLite DB plugins work similar |
|
||||
| Required | CurrentScan | Unique Prefix | Data source | Type | Link + Docs |
|
||||
|----------|-------------|---------------|--------------------|----------------|------------------------------------------------------------------|
|
||||
| | | APPRISE | Script | 💬 publisher | 📚[_publisher_apprise](/front/plugins/_publisher_apprise/) |
|
||||
| | Yes | ARPSCAN | Script | 🔍dev scanner | 📚[arp_scan](/front/plugins/arp_scan/) |
|
||||
| | | CSVBCKP | Script | ⚙ system | 📚[csv_backup](/front/plugins/csv_backup/) |
|
||||
| Yes* | | DBCLNP | Script | ⚙ system | 📚[db_cleanup](/front/plugins/db_cleanup/) |
|
||||
| | | DDNS | Script | ⚙ system | 📚[ddns_update](/front/plugins/ddns_update/) |
|
||||
| | Yes | DHCPLSS | Script | 🔍dev scanner | 📚[dhcp_leases](/front/plugins/dhcp_leases/) |
|
||||
| | | DHCPSRVS | Script | ♻ other | 📚[dhcp_servers](/front/plugins/dhcp_servers/) |
|
||||
| | Yes | INTRNT | Script | 🔍dev scanner | 📚[internet_ip](/front/plugins/internet_ip/) |
|
||||
| | | INTRSPD | Script | ♻ other | 📚[internet_speedtest](/front/plugins/internet_speedtest/) |
|
||||
| | | MAINT | Script | ⚙ system | 📚[maintenance](/front/plugins/maintenance/) |
|
||||
| | | MQTT | Script | 💬 publisher | 📚[_publisher_mqtt](/front/plugins/_publisher_mqtt/) |
|
||||
| Yes | | NEWDEV | Template | ⚙ system | 📚[newdev_template](/front/plugins/newdev_template/) |
|
||||
| | | NMAP | Script | ♻ other | 📚[nmap_scan](/front/plugins/nmap_scan/) |
|
||||
| | | NTFY | Script | 💬 publisher | 📚[_publisher_ntfy](/front/plugins/_publisher_ntfy/) |
|
||||
| | | PHOLUS | Script | ♻ other | 📚[pholus_scan](/front/plugins/pholus_scan/) |
|
||||
| | Yes | PIHOLE | External SQLite DB | 🔍dev scanner | 📚[pihole_scan](/front/plugins/pihole_scan/) |
|
||||
| | | PUSHSAFER | Script | 💬 publisher | 📚[_publisher_pushsafer](/front/plugins/_publisher_pushsafer/) |
|
||||
| | | SETPWD | Script | ⚙ system | 📚[set_password](/front/plugins/set_password/) |
|
||||
| | | SMTP | Script | 💬 publisher | 📚[_publisher_email](/front/plugins/_publisher_email/) |
|
||||
| | Yes | SNMPDSC | Script | 🔍dev scanner | 📚[snmp_discovery](/front/plugins/snmp_discovery/) |
|
||||
| | Yes** | UNDIS | Script | ♻ other | 📚[undiscoverables](/front/plugins/undiscoverables/) |
|
||||
| | Yes | UNFIMP | Script | 🔍dev scanner | 📚[unifi_import](/front/plugins/unifi_import/) |
|
||||
| | | VNDRPDT | Script | ⚙ system | 📚[vendor_update](/front/plugins/vendor_update/) |
|
||||
| | | WEBHOOK | Script | 💬 publisher | 📚[_publisher_webhook](/front/plugins/_publisher_webhook/) |
|
||||
| | | WEBMON | Script | ♻ other | 📚[website_monitor](/front/plugins/website_monitor/) |
|
||||
| N/A | | N/A | SQL query | | N/A, but the External SQLite DB plugins work similar |
|
||||
|
||||
|
||||
> \* The Undiscoverables plugin (`UNDIS`) inserts only user-specified dummy devices.
|
||||
>
|
||||
> \* The database cleanup plugin (`DBCLNP`) is not _required_ but the app will become unusable after a while if not executed.
|
||||
>
|
||||
> \** The Undiscoverables plugin (`UNDIS`) inserts only user-specified dummy devices.
|
||||
|
||||
> [!NOTE]
|
||||
> You soft-disable plugins via Settings or completely ignore plugins by placing a `ignore_plugin` file into the plugin directory. The difference is that ignored plugins don't show up anywhere in the UI (Settings, Device details, Plugins pages). The app skips ignored plugins completely. 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 a least some device-detecting plugins (that insert entries into the `CurrentScan` table) enabled, such as ARPSCAN or PIHOLE.
|
||||
> You soft-disable plugins via Settings or completely ignore plugins by placing a `ignore_plugin` file into the plugin directory. The difference is that ignored plugins don't show up anywhere in the UI (Settings, Device details, Plugins pages). The app skips ignored plugins completely. 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 a least some device-detecting plugins (that insert entries into the `CurrentScan` table) enabled, such as `ARPSCAN` or `PIHOLE`.
|
||||
|
||||
> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
|
||||
|
||||
@@ -81,13 +91,13 @@ Follow the below very carefully and check example plugin(s) if you'd like to wri
|
||||
* Adding form controls supported to display the data (Currently supported ones are listed in the section "UI settings in database_column_definitions" below)
|
||||
* ...
|
||||
|
||||
## ❗ Known issues:
|
||||
## ❗ Known limitations:
|
||||
|
||||
These issues will be hopefully fixed with time, so please don't report them. Instead, if you know how, feel free to investigate and submit a PR to fix the below. Keep the PRs small as it's easier to approve them:
|
||||
|
||||
* Existing plugin objects sometimes not interpreted correctly and a new object is created instead, resulting in duplicate entries. (race condition?)
|
||||
* Existing plugin objects are sometimes not interpreted correctly and a new object is created instead, resulting in duplicate entries. (race condition?)
|
||||
* Occasional (experienced twice) hanging of processing plugin script file.
|
||||
UI displays outdated values until the API endpoints get refreshed.
|
||||
* UI displays outdated values until the API endpoints get refreshed.
|
||||
|
||||
## Plugin file structure overview
|
||||
|
||||
@@ -133,6 +143,7 @@ Currently, these data sources are supported (valid `data_source` value).
|
||||
| Pialert DB query | `pialert-db-query` | yes | Executes a SQL query on the PiAlert 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 (`<general|system|scanner|other|publisher>`). |
|
||||
|
||||
|
||||
> 🔎Example
|
||||
@@ -540,8 +551,8 @@ Required attributes are:
|
||||
| `"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` |
|
||||
| | - `run` |
|
||||
| | - `"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. |
|
||||
|
||||
@@ -617,7 +628,8 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
|
||||
| Supported Types | Description |
|
||||
| -------------- | ----------- |
|
||||
| `label` | Displays a column only. |
|
||||
| `text` | Makes a column editable, and a save icon is displayed next to it. See below for information on `threshold`, `replace`. |
|
||||
| `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`. |
|
||||
| `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. |
|
||||
@@ -631,7 +643,8 @@ The UI will adjust how columns are displayed in the UI based on the resolvers de
|
||||
| `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.
|
||||
|
||||
8
front/plugins/_publisher_apprise/README.md
Executable file
8
front/plugins/_publisher_apprise/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
[Apprise](https://hub.docker.com/r/caronc/apprise) is a notification gateway/publisher that allows you to push notifications to 80+ different services.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
128
front/plugins/_publisher_apprise/apprise.py
Executable file
128
front/plugins/_publisher_apprise/apprise.py
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
import conf
|
||||
from plugin_helper import Plugin_Objects
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from notification import Notification_obj
|
||||
from database import DB
|
||||
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
pluginName = 'APPRISE'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Notification_obj instance
|
||||
notifications = Notification_obj(db)
|
||||
|
||||
# Retrieve new notifications
|
||||
new_notifications = notifications.getNew()
|
||||
|
||||
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
|
||||
for notification in new_notifications:
|
||||
|
||||
# Send notification
|
||||
result = send(notification["HTML"], notification["Text"])
|
||||
|
||||
# Log result
|
||||
plugin_objects.add_object(
|
||||
primaryId = pluginName,
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = notification["GUID"],
|
||||
watched2 = result,
|
||||
watched3 = 'null',
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = notification["GUID"]
|
||||
)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config():
|
||||
if get_setting_value('APPRISE_URL') == '' or get_setting_value('APPRISE_HOST') == '':
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def send(html, text):
|
||||
|
||||
payloadData = ''
|
||||
result = ''
|
||||
|
||||
# limit = 1024 * 1024 # 1MB limit (1024 bytes * 1024 bytes = 1MB)
|
||||
limit = get_setting_value('APPRISE_SIZE')
|
||||
|
||||
# truncate size
|
||||
if get_setting_value('APPRISE_PAYLOAD') == 'html':
|
||||
if len(html) > limit:
|
||||
payloadData = html[:limit] + "<h1>(text was truncated)</h1>"
|
||||
else:
|
||||
payloadData = html
|
||||
if get_setting_value('APPRISE_PAYLOAD') == 'text':
|
||||
if len(text) > limit:
|
||||
payloadData = text[:limit] + " (text was truncated)"
|
||||
else:
|
||||
payloadData = text
|
||||
|
||||
# Define Apprise compatible payload (https://github.com/caronc/apprise-api#stateless-solution)
|
||||
|
||||
_json_payload = {
|
||||
"urls": get_setting_value('APPRISE_URL'),
|
||||
"title": "Pi.Alert Notifications",
|
||||
"format": get_setting_value('APPRISE_PAYLOAD'),
|
||||
"body": payloadData
|
||||
}
|
||||
|
||||
try:
|
||||
# try runnning a subprocess
|
||||
p = subprocess.Popen(["curl","-i","-X", "POST" ,"-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), get_setting_value('APPRISE_HOST')], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
# write stdout and stderr into .log files for debugging if needed
|
||||
# Log the stdout and stderr
|
||||
mylog('debug', [stdout, stderr])
|
||||
|
||||
# log result
|
||||
result = stdout
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occurred, handle it
|
||||
mylog('none', [e.output])
|
||||
|
||||
# log result
|
||||
result = e.output
|
||||
|
||||
return result
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
430
front/plugins/_publisher_apprise/config.json
Executable file
430
front/plugins/_publisher_apprise/config.json
Executable file
@@ -0,0 +1,430 @@
|
||||
{
|
||||
"code_name": "_publisher_apprise",
|
||||
"unique_prefix": "APPRISE",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name" : [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Apprise publisher"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar Apprise"
|
||||
}
|
||||
],
|
||||
"icon":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "<i class=\"fa-solid fa-bullhorn\"></i>"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "A plugin to publish a notification via the Apprise gateway."
|
||||
}
|
||||
],
|
||||
"params" : [],
|
||||
"database_column_definitions":
|
||||
[
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "url",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sent when"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cambiado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Notification GUID"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-8",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Result"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comentarios"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Extra"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"settings":[
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["test"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "on_notification" ],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code": "en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cuando ejecuta"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enable sending notifications via <a target=\"_blank\" href=\"https://hub.docker.com/r/caronc/apprise\">Apprise</a>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar el envío de notificaciones a través de <a target=\"_blank\" href=\"https://hub.docker.com/r/caronc/apprise\">Apprise</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value":"python3 /home/pi/pialert/front/plugins/_publisher_apprise/apprise.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando a ejecutar"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string" : "Wartezeit"
|
||||
}],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "HOST",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Apprise host URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL del host de Apprise"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Apprise host URL starting with <code>http://</code> or <code>https://</code>. (do not forget to include <code>/notify</code> at the end)"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL del host de Apprise que comienza con <code>http://</code> o <code>https://</code>. (no olvide incluir <code>/notify</code> al final)"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "URL",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Apprise notification URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL de notificación de Apprise"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Apprise notification target URL. For example for Telegram it would be <code>tgram://{bot_token}/{chat_id}</code>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Informar de la URL de destino de la notificación. Por ejemplo, para Telegram sería <code>tgram://{bot_token}/{chat_id}</code>."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "PAYLOAD",
|
||||
"type": "text.select",
|
||||
"default_value": "html",
|
||||
"options": ["html", "text"],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Payload type"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tipo de carga"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Select the payoad type sent to Apprise. For example <code>html</code> works well with emails, <code>text</code> with chat apps, such as Telegram."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Seleccione el tipo de carga útil enviada a Apprise. Por ejemplo, <code>html</code> funciona bien con correos electrónicos, <code>text</code> con aplicaciones de chat, como Telegram."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "SIZE",
|
||||
"type": "integer",
|
||||
"default_value": 1024,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Max payload size"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tamaño máximo de carga útil"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "The maximum size of the apprise payload as number of characters in the passed string. If above limit, it will be truncated and a <code>(text was truncated)</code> message is appended."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "El tamaño máximo de la carga útil de información como número de caracteres en la cadena pasada. Si supera el límite, se truncará y se agregará un mensaje <code>(text was truncated)</code>."
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
8
front/plugins/_publisher_email/README.md
Executable file
8
front/plugins/_publisher_email/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
A simple EMail (SMTP) notification gateway publisher. Check the [SMTP docs](/docs/SMTP.md) for additional help.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
689
front/plugins/_publisher_email/config.json
Executable file
689
front/plugins/_publisher_email/config.json
Executable file
@@ -0,0 +1,689 @@
|
||||
{
|
||||
"code_name": "_publisher_email",
|
||||
"unique_prefix": "SMTP",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Email publisher (SMTP)"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Habilitar email (SMTP)"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-at\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to publish a notification via Email (SMTP) gateway."
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "url",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Sent when"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Notification GUID"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-8",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Result"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comentarios"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Extra"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": [
|
||||
"test"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"on_notification"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuando ejecuta"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Enable sending notifications via the Email (SMTP) gateway."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Si está habilitado, se envía un correo electrónico con una lista de cambios a los que se ha suscrito. Complete también todas las configuraciones restantes relacionadas con la configuración de SMTP a continuación"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/_publisher_email/email_smtp.py",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 20,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wartezeit"
|
||||
}
|
||||
],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "SERVER",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "SMTP server URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "URL del servidor SMTP"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The SMTP server host URL. For example <code>smtp-relay.sendinblue.com</code>. To use Gmail as an SMTP server <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SMTP.md\">follow this guide</a>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "La URL del host del servidor SMTP. Por ejemplo, <code>smtp-relay.sendinblue.com</code>. Para utilizar Gmail como servidor SMTP <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SMTP.md\">siga esta guía</a >"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "PORT",
|
||||
"type": "integer",
|
||||
"default_value": 587,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "SMTP server PORT"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Puerto del servidor SMTP"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Port number used for the SMTP connection. Set to <code>0</code> if you do not want to use a port when connecting to the SMTP server."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Número de puerto utilizado para la conexión SMTP. Establézcalo en <code>0</code> si no desea utilizar un puerto al conectarse al servidor SMTP."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "SKIP_LOGIN",
|
||||
"type": "boolean",
|
||||
"default_value": false,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Skip authentication"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Omitir autenticación"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Do not use authentication when connecting to the SMTP server."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "No utilice la autenticación cuando se conecte al servidor SMTP."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "USER",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "SMTP user"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Nombre de usuario SMTP"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The user name used to login into the SMTP server (sometimes a full email address)."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "El nombre de usuario utilizado para iniciar sesión en el servidor SMTP (a veces, una dirección de correo electrónico completa)."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "PASS",
|
||||
"type": "password",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "SMTP password"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Contraseña de SMTP"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The SMTP server password."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "La contraseña del servidor SMTP."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "SKIP_TLS",
|
||||
"type": "boolean",
|
||||
"default_value": false,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Do not use TLS"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "No usar TLS"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Disable TLS when connecting to your SMTP server."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Deshabilite TLS cuando se conecte a su servidor SMTP."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "FORCE_SSL",
|
||||
"type": "boolean",
|
||||
"default_value": false,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Force SSL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Forzar SSL"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Force SSL when connecting to your SMTP server."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Forzar SSL al conectarse a su servidor SMTP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_TO",
|
||||
"type": "text",
|
||||
"default_value": "user@gmail.com",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send email to"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Enviar el email a"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Email address to which the notification will be send to."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dirección de correo electrónico a la que se enviará la notificación."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_FROM",
|
||||
"type": "text",
|
||||
"default_value": "Pi.Alert <user@gmail.com>",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Email subject"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Asunto del email"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Notification email subject line. Some SMTP servers need this to be an email."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Asunto del correo electrónico de notificación."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
199
front/plugins/_publisher_email/email_smtp.py
Executable file
199
front/plugins/_publisher_email/email_smtp.py
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
from datetime import datetime
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.header import Header
|
||||
from email.utils import parseaddr
|
||||
import smtplib
|
||||
import socket
|
||||
import ssl
|
||||
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
# PiAlert modules
|
||||
import conf
|
||||
from plugin_helper import Plugin_Objects
|
||||
from logger import mylog, append_line_to_file, print_log
|
||||
from helper import timeNowTZ, get_setting_value, hide_email
|
||||
from notification import Notification_obj
|
||||
from database import DB
|
||||
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
pluginName = 'SMTP'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Notification_obj instance
|
||||
notifications = Notification_obj(db)
|
||||
|
||||
# Retrieve new notifications
|
||||
new_notifications = notifications.getNew()
|
||||
|
||||
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
|
||||
for notification in new_notifications:
|
||||
|
||||
# Send notification
|
||||
result = send(notification["HTML"], notification["Text"])
|
||||
|
||||
# Log result
|
||||
plugin_objects.add_object(
|
||||
primaryId = pluginName,
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = notification["GUID"],
|
||||
watched2 = result,
|
||||
watched3 = 'null',
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = notification["GUID"]
|
||||
)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config ():
|
||||
|
||||
server = get_setting_value('SMTP_SERVER')
|
||||
report_to = get_setting_value("SMTP_REPORT_TO")
|
||||
report_from = get_setting_value("SMTP_REPORT_FROM")
|
||||
|
||||
if server == '' or report_from == '' or report_to == '':
|
||||
mylog('none', ['[Email Check Config] ⚠ ERROR: Email service not set up correctly. Check your pialert.conf SMTP_*, SMTP_REPORT_FROM and SMTP_REPORT_TO variables.'])
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def send(pHTML, pText):
|
||||
|
||||
mylog('debug', [f'[{pluginName}] SMTP_REPORT_TO: {hide_email(str(get_setting_value("SMTP_REPORT_TO")))} SMTP_USER: {hide_email(str(get_setting_value("SMTP_USER")))}'])
|
||||
|
||||
|
||||
subject, from_email, to_email, message_html, message_text = sanitize_email_content('Pi.Alert Report', get_setting_value("SMTP_REPORT_FROM"), get_setting_value("SMTP_REPORT_TO"), pHTML, pText)
|
||||
|
||||
# Compose email
|
||||
msg = MIMEMultipart('alternative')
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = from_email
|
||||
msg['To'] = to_email
|
||||
msg.attach (MIMEText (message_text, 'plain'))
|
||||
msg.attach (MIMEText (message_html, 'html'))
|
||||
|
||||
# Set a timeout for the SMTP connection (in seconds)
|
||||
smtp_timeout = 30
|
||||
|
||||
mylog('debug', ['Trying to open connection to ' + str(get_setting_value('SMTP_SERVER')) + ':' + str(get_setting_value('SMTP_PORT'))])
|
||||
|
||||
if get_setting_value("LOG_LEVEL") == 'debug':
|
||||
|
||||
send_email(msg)
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
send_email(msg)
|
||||
|
||||
except smtplib.SMTPAuthenticationError as e:
|
||||
mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPAuthenticationError)'])
|
||||
mylog('none', [' ERROR: Double-check your SMTP_USER and SMTP_PASS settings.)'])
|
||||
mylog('none', [' ERROR: ', str(e)])
|
||||
except smtplib.SMTPServerDisconnected as e:
|
||||
mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPServerDisconnected)'])
|
||||
mylog('none', [' ERROR: ', str(e)])
|
||||
except socket.gaierror as e:
|
||||
mylog('none', [' ERROR: Could not resolve hostname (socket.gaierror)'])
|
||||
mylog('none', [' ERROR: ', str(e)])
|
||||
except ssl.SSLError as e:
|
||||
mylog('none', [' ERROR: Could not establish SSL connection (ssl.SSLError)'])
|
||||
mylog('none', [' ERROR: Are you sure you need SMTP_FORCE_SSL enabled? Check your SMTP provider docs.'])
|
||||
mylog('none', [' ERROR: ', str(e)])
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
def send_email(msg):
|
||||
# Send mail
|
||||
if get_setting_value('SMTP_FORCE_SSL'):
|
||||
mylog('debug', ['SMTP_FORCE_SSL == True so using .SMTP_SSL()'])
|
||||
if get_setting_value("SMTP_PORT") == 0:
|
||||
mylog('debug', ['SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER)'])
|
||||
smtp_connection = smtplib.SMTP_SSL(get_setting_value('SMTP_SERVER'))
|
||||
else:
|
||||
mylog('debug', ['SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER, SMTP_PORT)'])
|
||||
smtp_connection = smtplib.SMTP_SSL(get_setting_value('SMTP_SERVER'), get_setting_value('SMTP_PORT'), timeout=smtp_timeout)
|
||||
|
||||
else:
|
||||
mylog('debug', ['SMTP_FORCE_SSL == False so using .SMTP()'])
|
||||
if get_setting_value("SMTP_PORT") == 0:
|
||||
mylog('debug', ['SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER)'])
|
||||
smtp_connection = smtplib.SMTP (get_setting_value('SMTP_SERVER'))
|
||||
else:
|
||||
mylog('debug', ['SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER, SMTP_PORT)'])
|
||||
smtp_connection = smtplib.SMTP (get_setting_value('SMTP_SERVER'), get_setting_value('SMTP_PORT'))
|
||||
|
||||
mylog('debug', ['Setting SMTP debug level'])
|
||||
|
||||
# Log level set to debug of the communication between SMTP server and client
|
||||
if get_setting_value('LOG_LEVEL') == 'debug':
|
||||
smtp_connection.set_debuglevel(1)
|
||||
|
||||
mylog('debug', [ 'Sending .ehlo()'])
|
||||
smtp_connection.ehlo()
|
||||
|
||||
if not get_setting_value('SMTP_SKIP_TLS'):
|
||||
mylog('debug', ['SMTP_SKIP_TLS == False so sending .starttls()'])
|
||||
smtp_connection.starttls()
|
||||
mylog('debug', ['SMTP_SKIP_TLS == False so sending .ehlo()'])
|
||||
smtp_connection.ehlo()
|
||||
if not get_setting_value('SMTP_SKIP_LOGIN'):
|
||||
mylog('debug', ['SMTP_SKIP_LOGIN == False so sending .login()'])
|
||||
smtp_connection.login (get_setting_value('SMTP_USER'), get_setting_value('SMTP_PASS'))
|
||||
|
||||
mylog('debug', ['Sending .sendmail()'])
|
||||
smtp_connection.sendmail (get_setting_value("SMTP_REPORT_FROM"), get_setting_value("SMTP_REPORT_TO"), msg.as_string())
|
||||
smtp_connection.quit()
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
def sanitize_email_content(subject, from_email, to_email, message_html, message_text):
|
||||
# Validate and sanitize subject
|
||||
subject = Header(subject, 'utf-8').encode()
|
||||
|
||||
# Validate and sanitize sender's email address
|
||||
from_name, from_address = parseaddr(from_email)
|
||||
from_email = Header(from_name, 'utf-8').encode() + ' <' + from_address + '>'
|
||||
|
||||
# Validate and sanitize recipient's email address
|
||||
to_name, to_address = parseaddr(to_email)
|
||||
to_email = Header(to_name, 'utf-8').encode() + ' <' + to_address + '>'
|
||||
|
||||
# Validate and sanitize message content
|
||||
# Remove potentially problematic characters
|
||||
message_html = re.sub(r'[^\x00-\x7F]+', ' ', message_html)
|
||||
message_text = re.sub(r'[^\x00-\x7F]+', ' ', message_text)
|
||||
|
||||
return subject, from_email, to_email, message_html, message_text
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
8
front/plugins/_publisher_mqtt/README.md
Executable file
8
front/plugins/_publisher_mqtt/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
- Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md) via the MQTT Mosquito broker.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
467
front/plugins/_publisher_mqtt/config.json
Executable file
467
front/plugins/_publisher_mqtt/config.json
Executable file
@@ -0,0 +1,467 @@
|
||||
{
|
||||
"code_name": "_publisher_mqtt",
|
||||
"unique_prefix": "MQTT",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name" : [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT publisher"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar MQTT"
|
||||
}
|
||||
],
|
||||
"icon":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "<i class=\"fa-solid fa-square-rss\"></i>"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "A plugin to publish a notification via the Apprise gateway."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
{
|
||||
"name" : "devices",
|
||||
"type" : "sql",
|
||||
"value" : "SELECT dev_LastIP from DEVICES",
|
||||
"timeoutMultiplier" : true
|
||||
}
|
||||
],
|
||||
"database_column_definitions":
|
||||
[
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT Device ID"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sensor Name"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sent when"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cambiado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Device name"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sensor type"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Hash"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value4",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_mac",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Device"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comentarios"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Extra"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"settings":[
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["test"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "on_notification" ],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code": "en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cuando ejecuta"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enable sending notifications via <a target=\"_blank\" href=\"https://www.home-assistant.io/integrations/mqtt/\">MQTT</a> to your Home Assistance instance."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar el envío de notificaciones a través de <a target=\"_blank\" href=\"https://www.home-assistant.io/integrations/mqtt/\">MQTT</a> a su Home Assistance."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value":"python3 /home/pi/pialert/front/plugins/_publisher_mqtt/mqtt.py devices={devices}",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando a ejecutar"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string" : "Wartezeit"
|
||||
}],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "BROKER",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT broker URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL del broker MQTT"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT host URL (do not include <code>http://</code> or <code>https://</code>)."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL del host MQTT (no incluya <code>http://</code> o <code>https://</code>)."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "PORT",
|
||||
"type": "integer",
|
||||
"default_value": 1883,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT broker port"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Puerto del broker MQTT"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Port number where the broker is listening. Usually <code>1883</code>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Puerto donde escucha el broker MQTT. Normalmente <code>1883</code>."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "USER",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT user"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Usuario de MQTT"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "User name used to login into your MQTT broker instance."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Nombre de usuario utilizado para iniciar sesión en su instancia de agente de MQTT."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "PASSWORD",
|
||||
"type": "password",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT password"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Contraseña de MQTT"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Password used to login into your MQTT broker instance."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Contraseña utilizada para iniciar sesión en su instancia de agente de MQTT."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "QOS",
|
||||
"type": "integer.select",
|
||||
"default_value": 0,
|
||||
"options": [0, 1, 2],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT Quality of Service"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Calidad de servicio MQTT"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Quality of service setting for MQTT message sending. <code>0</code> - Low quality to <code>2</code> - High quality. The higher the quality the longer the delay."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Configuración de calidad de servicio para el envío de mensajes MQTT. <code>0</code>: baja calidad a <code>2</code>: alta calidad. Cuanto mayor sea la calidad, mayor será el retraso."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "DELAY_SEC",
|
||||
"type": "integer",
|
||||
"default_value": 2,
|
||||
"options": [2, 3, 4, 5],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "MQTT delay per device"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Retraso de MQTT por dispositivo"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "A little hack - delay adding to the queue in case the process is restarted and previous publish processes aborted (it takes ~<code>2</code>s to update a sensor config on the broker). Tested with <code>2</code>-<code>3</code> seconds of delay. This delay is only applied when devices are created (during the first notification loop). It doesn not affect subsequent scans or notifications."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Un pequeño truco: retrase la adición a la cola en caso de que el proceso se reinicie y los procesos de publicación anteriores se anulen (se necesitan ~<code>2</code>s para actualizar la configuración de un sensor en el intermediario). Probado con <code>2</code>-<code>3</code> segundos de retraso. Este retraso solo se aplica cuando se crean dispositivos (durante el primer bucle de notificación). No afecta los escaneos o notificaciones posteriores."
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,23 +1,76 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from datetime import datetime
|
||||
import time
|
||||
import re
|
||||
from paho.mqtt import client as mqtt_client
|
||||
import hashlib
|
||||
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
# PiAlert modules
|
||||
import conf
|
||||
from logger import mylog
|
||||
from database import get_all_devices, get_device_stats
|
||||
from helper import bytes_to_string, sanitize_string
|
||||
from const import apiPath
|
||||
from plugin_utils import getPluginObject
|
||||
from plugin_helper import Plugin_Objects
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value, bytes_to_string, sanitize_string
|
||||
from notification import Notification_obj
|
||||
from database import DB, get_all_devices, get_device_stats
|
||||
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
# Create an MD5 hash object
|
||||
md5_hash = hashlib.md5()
|
||||
|
||||
pluginName = 'MQTT'
|
||||
module_name = pluginName
|
||||
|
||||
# globals
|
||||
|
||||
mqtt_sensors = []
|
||||
mqtt_connected_to_broker = False
|
||||
client = None # mqtt client
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
mqtt_start(db)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# MQTT
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config():
|
||||
if conf.MQTT_BROKER == '' or conf.MQTT_PORT == '' or conf.MQTT_USER == '' or conf.MQTT_PASSWORD == '':
|
||||
mylog('none', ['[Check Config] Error: MQTT service not set up correctly. Check your pialert.conf MQTT_* variables.'])
|
||||
if get_setting_value('MQTT_BROKER') == '' or get_setting_value('MQTT_PORT') == '' or get_setting_value('MQTT_USER') == '' or get_setting_value('MQTT_PASSWORD') == '':
|
||||
mylog('none', ['[Check Config] ⚠ ERROR: MQTT service not set up correctly. Check your pialert.conf MQTT_* variables.'])
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
@@ -25,13 +78,55 @@ def check_config():
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
class sensor_config:
|
||||
def __init__(self, deviceId, deviceName, sensorType, sensorName, icon):
|
||||
def __init__(self, deviceId, deviceName, sensorType, sensorName, icon, mac):
|
||||
self.deviceId = deviceId
|
||||
self.deviceName = deviceName
|
||||
self.sensorType = sensorType
|
||||
self.sensorName = sensorName
|
||||
self.icon = icon
|
||||
self.hash = str(hash(str(deviceId) + str(deviceName)+ str(sensorType)+ str(sensorName)+ str(icon)))
|
||||
|
||||
# Define your input string
|
||||
input_string = str(deviceId) + str(deviceName) + str(sensorType) + str(sensorName) + str(icon)
|
||||
|
||||
# Hash the input string and convert the hash to a string
|
||||
# Update the hash object with the bytes of the input string
|
||||
md5_hash.update(input_string.encode('utf-8'))
|
||||
|
||||
# Get the hexadecimal representation of the MD5 hash
|
||||
md5_hash_hex = md5_hash.hexdigest()
|
||||
hash_value = str(md5_hash_hex)
|
||||
|
||||
self.hash = hash_value
|
||||
|
||||
plugObj = getPluginObject({"Plugin":"MQTT", "Watched_Value3":hash_value})
|
||||
|
||||
# mylog('verbose', [f"[{pluginName}] Previous plugin object entry: {json.dumps(plugObj)}"])
|
||||
|
||||
if plugObj == {}:
|
||||
self.isNew = True
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry mac : {mac}"])
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry input_string : {input_string}"])
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry hash_value : {hash_value}"])
|
||||
else:
|
||||
self.isNew = False
|
||||
|
||||
|
||||
# Log sensor
|
||||
global plugin_objects
|
||||
|
||||
if mac == '':
|
||||
mac = "N/A"
|
||||
|
||||
plugin_objects.add_object(
|
||||
primaryId = deviceId,
|
||||
secondaryId = sensorName,
|
||||
watched1 = deviceName,
|
||||
watched2 = sensorType,
|
||||
watched3 = hash_value,
|
||||
watched4 = mac,
|
||||
extra = input_string,
|
||||
foreignKey = mac
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
@@ -41,14 +136,14 @@ def publish_mqtt(client, topic, message):
|
||||
result = client.publish(
|
||||
topic=topic,
|
||||
payload=message,
|
||||
qos=conf.MQTT_QOS,
|
||||
qos=get_setting_value('MQTT_QOS'),
|
||||
retain=True,
|
||||
)
|
||||
|
||||
status = result[0]
|
||||
|
||||
if status != 0:
|
||||
mylog('minimal', ["Waiting to reconnect to MQTT broker"])
|
||||
mylog('minimal', [f"[{pluginName}] Waiting to reconnect to MQTT broker"])
|
||||
time.sleep(0.1)
|
||||
return True
|
||||
|
||||
@@ -67,74 +162,79 @@ def create_generic_device(client):
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def create_sensor(client, deviceId, deviceName, sensorType, sensorName, icon):
|
||||
|
||||
new_sensor_config = sensor_config(deviceId, deviceName, sensorType, sensorName, icon)
|
||||
def create_sensor(client, deviceId, deviceName, sensorType, sensorName, icon, mac=""):
|
||||
|
||||
# check if config already in list and if not, add it, otherwise skip
|
||||
is_unique = True
|
||||
global mqtt_sensors
|
||||
|
||||
for sensor in conf.mqtt_sensors:
|
||||
if sensor.hash == new_sensor_config.hash:
|
||||
is_unique = False
|
||||
break
|
||||
new_sensor_config = sensor_config(deviceId, deviceName, sensorType, sensorName, icon, mac)
|
||||
|
||||
# save if unique
|
||||
if is_unique:
|
||||
# save if new
|
||||
if new_sensor_config.isNew:
|
||||
mylog('minimal', [f"[{pluginName}] Publishing sensor number {len(mqtt_sensors)}"])
|
||||
publish_sensor(client, new_sensor_config)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def publish_sensor(client, sensorConf):
|
||||
def publish_sensor(client, sensorConfig):
|
||||
|
||||
global mqtt_sensors
|
||||
|
||||
message = '{ \
|
||||
"name":"'+ sensorConf.deviceName +' '+sensorConf.sensorName+'", \
|
||||
"state_topic":"system-sensors/'+sensorConf.sensorType+'/'+sensorConf.deviceId+'/state", \
|
||||
"value_template":"{{value_json.'+sensorConf.sensorName+'}}", \
|
||||
"unique_id":"'+sensorConf.deviceId+'_sensor_'+sensorConf.sensorName+'", \
|
||||
"name":"'+ sensorConfig.deviceName +' '+sensorConfig.sensorName+'", \
|
||||
"state_topic":"system-sensors/'+sensorConfig.sensorType+'/'+sensorConfig.deviceId+'/state", \
|
||||
"value_template":"{{value_json.'+sensorConfig.sensorName+'}}", \
|
||||
"unique_id":"'+sensorConfig.deviceId+'_sensor_'+sensorConfig.sensorName+'", \
|
||||
"device": \
|
||||
{ \
|
||||
"identifiers": ["'+sensorConf.deviceId+'_sensor"], \
|
||||
"identifiers": ["'+sensorConfig.deviceId+'_sensor"], \
|
||||
"manufacturer": "PiAlert", \
|
||||
"name":"'+sensorConf.deviceName+'" \
|
||||
"name":"'+sensorConfig.deviceName+'" \
|
||||
}, \
|
||||
"icon":"mdi:'+sensorConf.icon+'" \
|
||||
"icon":"mdi:'+sensorConfig.icon+'" \
|
||||
}'
|
||||
|
||||
topic='homeassistant/'+sensorConf.sensorType+'/'+sensorConf.deviceId+'/'+sensorConf.sensorName+'/config'
|
||||
topic='homeassistant/'+sensorConfig.sensorType+'/'+sensorConfig.deviceId+'/'+sensorConfig.sensorName+'/config'
|
||||
|
||||
# add the sensor to the global list to keep track of succesfully added sensors
|
||||
if publish_mqtt(client, topic, message):
|
||||
# hack - delay adding to the queue in case the process is
|
||||
time.sleep(conf.MQTT_DELAY_SEC) # restarted and previous publish processes aborted
|
||||
time.sleep(get_setting_value('MQTT_DELAY_SEC')) # restarted and previous publish processes aborted
|
||||
# (it takes ~2s to update a sensor config on the broker)
|
||||
conf.mqtt_sensors.append(sensorConf)
|
||||
mqtt_sensors.append(sensorConfig)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def mqtt_create_client():
|
||||
def mqtt_create_client():
|
||||
def on_disconnect(client, userdata, rc):
|
||||
conf.mqtt_connected_to_broker = False
|
||||
|
||||
global mqtt_connected_to_broker
|
||||
|
||||
mqtt_connected_to_broker = False
|
||||
|
||||
# not sure is below line is correct / necessary
|
||||
# client = mqtt_create_client()
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
|
||||
if rc == 0:
|
||||
mylog('verbose', [" Connected to broker"])
|
||||
conf.mqtt_connected_to_broker = True # Signal connection
|
||||
else:
|
||||
mylog('none', [" Connection failed"])
|
||||
conf.mqtt_connected_to_broker = False
|
||||
global mqtt_connected_to_broker
|
||||
|
||||
if rc == 0:
|
||||
mylog('verbose', [f"[{pluginName}] Connected to broker"])
|
||||
mqtt_connected_to_broker = True # Signal connection
|
||||
else:
|
||||
mylog('none', [f"[{pluginName}] Connection failed"])
|
||||
mqtt_connected_to_broker = False
|
||||
|
||||
|
||||
global client
|
||||
|
||||
client = mqtt_client.Client('PiAlert') # Set Connecting Client ID
|
||||
client.username_pw_set(conf.MQTT_USER, conf.MQTT_PASSWORD)
|
||||
client.username_pw_set(get_setting_value('MQTT_USER'), get_setting_value('MQTT_PASSWORD'))
|
||||
client.on_connect = on_connect
|
||||
client.on_disconnect = on_disconnect
|
||||
client.connect(conf.MQTT_BROKER, conf.MQTT_PORT)
|
||||
client.connect(get_setting_value('MQTT_BROKER'), get_setting_value('MQTT_PORT'))
|
||||
client.loop_start()
|
||||
|
||||
return client
|
||||
@@ -142,13 +242,12 @@ def mqtt_create_client():
|
||||
#-------------------------------------------------------------------------------
|
||||
def mqtt_start(db):
|
||||
|
||||
#global client
|
||||
global client, mqtt_connected_to_broker
|
||||
|
||||
if conf.mqtt_connected_to_broker == False:
|
||||
conf.mqtt_connected_to_broker = True
|
||||
conf.client = mqtt_create_client()
|
||||
if mqtt_connected_to_broker == False:
|
||||
mqtt_connected_to_broker = True
|
||||
client = mqtt_create_client()
|
||||
|
||||
client = conf.client
|
||||
# General stats
|
||||
|
||||
# Create a generic device for overal stats
|
||||
@@ -178,21 +277,23 @@ def mqtt_start(db):
|
||||
# Get all devices
|
||||
devices = get_all_devices(db)
|
||||
|
||||
sec_delay = len(devices) * int(conf.MQTT_DELAY_SEC)*5
|
||||
sec_delay = len(devices) * int(get_setting_value('MQTT_DELAY_SEC'))*5
|
||||
|
||||
mylog('minimal', [" Estimated delay: ", (sec_delay), 's ', '(', round(sec_delay/60,1) , 'min)' ])
|
||||
mylog('minimal', [f"[{pluginName}] Estimated delay: ", (sec_delay), 's ', '(', round(sec_delay/60,1) , 'min)' ])
|
||||
|
||||
for device in devices:
|
||||
|
||||
for device in devices:
|
||||
|
||||
|
||||
# Create devices in Home Assistant - send config messages
|
||||
deviceId = 'mac_' + device["dev_MAC"].replace(" ", "").replace(":", "_").lower()
|
||||
deviceNameDisplay = re.sub('[^a-zA-Z0-9-_\s]', '', device["dev_Name"])
|
||||
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'last_ip', 'ip-network')
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'binary_sensor', 'is_present', 'wifi')
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'mac_address', 'folder-key-network')
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'is_new', 'bell-alert-outline')
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'vendor', 'cog')
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'last_ip', 'ip-network', device["dev_MAC"])
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'binary_sensor', 'is_present', 'wifi', device["dev_MAC"])
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'mac_address', 'folder-key-network', device["dev_MAC"])
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'is_new', 'bell-alert-outline', device["dev_MAC"])
|
||||
create_sensor(client, deviceId, deviceNameDisplay, 'sensor', 'vendor', 'cog', device["dev_MAC"])
|
||||
|
||||
# update device sensors in home assistant
|
||||
|
||||
@@ -242,4 +343,14 @@ def to_binary_sensor(input):
|
||||
elif isinstance(input, bytes):
|
||||
if bytes_to_string(input) == "1":
|
||||
result = "ON"
|
||||
return result
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
# -------------INIT---------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
|
||||
|
||||
8
front/plugins/_publisher_ntfy/README.md
Executable file
8
front/plugins/_publisher_ntfy/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
A plugin to publish a notification via the NTFY gateway. Enable sending notifications via <a target="_blank" href="https://ntfy.sh/">NTFY</a>. Supports authentication.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
390
front/plugins/_publisher_ntfy/config.json
Executable file
390
front/plugins/_publisher_ntfy/config.json
Executable file
@@ -0,0 +1,390 @@
|
||||
{
|
||||
"code_name": "_publisher_ntfy",
|
||||
"unique_prefix": "NTFY",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name" : [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY publisher"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar NTFY"
|
||||
}
|
||||
],
|
||||
"icon":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "<i class=\"fa-solid fa-terminal\"></i>"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "A plugin to publish a notification via the NTFY gateway."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
],
|
||||
"database_column_definitions":
|
||||
[
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sent when"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Notification GUID"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response code"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value4",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "device_mac",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Device"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comentarios"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Extra"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"settings":[
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["test"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "on_notification" ],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code": "en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cuando ejecuta"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enable sending notifications via <a target=\"_blank\" href=\"https://ntfy.sh/\">NTFY</a>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar el envío de notificaciones a través de <a target=\"_blank\" href=\"https://ntfy.sh/\">NTFY</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value":"python3 /home/pi/pialert/front/plugins/_publisher_ntfy/ntfy.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando a ejecutar"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string" : "Wartezeit"
|
||||
}],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "HOST",
|
||||
"type": "text",
|
||||
"default_value": "https://ntfy.sh",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY host URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL del host NTFY"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY host URL starting with <code>http://</code> or <code>https://</code>. You can use the hosted instance on <a target=\"_blank\" href=\"https://ntfy.sh/\">https://ntfy.sh</a> by simply entering <code>https://ntfy.sh</code>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL de host NTFY que comienza con <code>http://</code> o <code>https://</code>. Puede usar la instancia alojada en <a target=\"_blank\" href=\"https://ntfy.sh/\">https://ntfy.sh</a> simplemente ingresando <code>https://ntfy. sh</código>."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "TOPIC",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY topic"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tema de NTFY"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Your secret topic."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tu tema secreto."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "USER",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY user"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Usuario de NTFY"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enter user if you need (host) an instance with enabled authetication."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Ingrese usuario si necesita (alojar) una instancia con autenticación habilitada."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "PASSWORD",
|
||||
"type": "password",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "NTFY password"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Contraseña de NTFY"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enter password if you need (host) an instance with enabled authetication."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Ingrese la contraseña si necesita (host) una instancia con autenticación habilitada."
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
132
front/plugins/_publisher_ntfy/ntfy.py
Executable file
132
front/plugins/_publisher_ntfy/ntfy.py
Executable file
@@ -0,0 +1,132 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from base64 import b64encode
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
import conf
|
||||
from plugin_helper import Plugin_Objects, handleEmpty
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from notification import Notification_obj
|
||||
from database import DB
|
||||
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
pluginName = 'NTFY'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Notification_obj instance
|
||||
notifications = Notification_obj(db)
|
||||
|
||||
# Retrieve new notifications
|
||||
new_notifications = notifications.getNew()
|
||||
|
||||
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
|
||||
for notification in new_notifications:
|
||||
|
||||
# Send notification
|
||||
response_text, response_status_code = send(notification["HTML"], notification["Text"])
|
||||
|
||||
# Log result
|
||||
plugin_objects.add_object(
|
||||
primaryId = pluginName,
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = notification["GUID"],
|
||||
watched2 = handleEmpty(response_text),
|
||||
watched3 = response_status_code,
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = notification["GUID"]
|
||||
)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config():
|
||||
if get_setting_value('NTFY_HOST') == '' or get_setting_value('NTFY_TOPIC') == '':
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def send(html, text):
|
||||
|
||||
response_text = ''
|
||||
response_status_code = ''
|
||||
|
||||
|
||||
headers = {
|
||||
"Title": "Pi.Alert Notification",
|
||||
"Actions": "view, Open Dashboard, "+ get_setting_value('REPORT_DASHBOARD_URL'),
|
||||
"Priority": "urgent",
|
||||
"Tags": "warning"
|
||||
}
|
||||
|
||||
# if username and password are set generate hash and update header
|
||||
if get_setting_value('NTFY_USER') != "" and get_setting_value('NTFY_PASSWORD') != "":
|
||||
# Generate hash for basic auth
|
||||
# usernamepassword = "{}:{}".format(get_setting_value('NTFY_USER'),get_setting_value('NTFY_PASSWORD'))
|
||||
basichash = b64encode(bytes(get_setting_value('NTFY_USER') + ':' + get_setting_value('NTFY_PASSWORD'), "utf-8")).decode("ascii")
|
||||
|
||||
# add authorization header with hash
|
||||
headers["Authorization"] = "Basic {}".format(basichash)
|
||||
|
||||
try:
|
||||
response = requests.post("{}/{}".format( get_setting_value('NTFY_HOST'),
|
||||
get_setting_value('NTFY_TOPIC')),
|
||||
data = text,
|
||||
headers = headers)
|
||||
|
||||
response_status_code = response.status_code
|
||||
|
||||
|
||||
|
||||
# Check if the request was successful (status code 200)
|
||||
if response_status_code == 200:
|
||||
response_text = response.text # This captures the response body/message
|
||||
else:
|
||||
response_text = json.dumps(response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: ', e])
|
||||
|
||||
response_text = e
|
||||
|
||||
return response_text, response_status_code
|
||||
|
||||
return response_text, response_status_code
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
8
front/plugins/_publisher_pushsafer/README.md
Executable file
8
front/plugins/_publisher_pushsafer/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
A plugin to publish a notification via the Pushsafer gateway. Enable sending notifications via <a target="_blank" href="https://www.pushsafer.com/">Pushsafer</a>.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
321
front/plugins/_publisher_pushsafer/config.json
Executable file
321
front/plugins/_publisher_pushsafer/config.json
Executable file
@@ -0,0 +1,321 @@
|
||||
{
|
||||
"code_name": "_publisher_pushsafer",
|
||||
"unique_prefix": "PUSHSAFER",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name" : [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Pushsafer publisher"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar Pushsafer"
|
||||
}
|
||||
],
|
||||
"icon":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "<i class=\"fa-solid fa-bell\"></i>"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "A plugin to publish a notification via the Pushsafer gateway."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
],
|
||||
"database_column_definitions":
|
||||
[
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sent when"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Notification GUID"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response code"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value4",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "device_mac",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Device"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comentarios"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Extra"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"settings":[
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["test"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "on_notification" ],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code": "en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cuando ejecuta"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enable sending notifications via <a target=\"_blank\" href=\"https://www.pushsafer.com/\">Pushsafer</a>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar el envío de notificaciones a través de <a target=\"_blank\" href=\"https://www.pushsafer.com/\">Pushsafer</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value":"python3 /home/pi/pialert/front/plugins/_publisher_pushsafer/pushsafer.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando a ejecutar"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string" : "Wartezeit"
|
||||
}],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "TOKEN",
|
||||
"type": "text",
|
||||
"default_value": "ApiKey",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Pushsafer token"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Token de Pushsafer"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Your secret Pushsafer API key (token)."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Su clave secreta de la API de Pushsafer (token)."
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
133
front/plugins/_publisher_pushsafer/pushsafer.py
Executable file
133
front/plugins/_publisher_pushsafer/pushsafer.py
Executable file
@@ -0,0 +1,133 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from base64 import b64encode
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
import conf
|
||||
from plugin_helper import Plugin_Objects, handleEmpty
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value, hide_string
|
||||
from notification import Notification_obj
|
||||
from database import DB
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
pluginName = 'PUSHSAFER'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Notification_obj instance
|
||||
notifications = Notification_obj(db)
|
||||
|
||||
# Retrieve new notifications
|
||||
new_notifications = notifications.getNew()
|
||||
|
||||
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
|
||||
for notification in new_notifications:
|
||||
|
||||
# Send notification
|
||||
response_text, response_status_code = send(notification["Text"])
|
||||
|
||||
# Log result
|
||||
plugin_objects.add_object(
|
||||
primaryId = pluginName,
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = notification["GUID"],
|
||||
watched2 = handleEmpty(response_text),
|
||||
watched3 = response_status_code,
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = notification["GUID"]
|
||||
)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def send(text):
|
||||
|
||||
response_text = ''
|
||||
response_status_code = ''
|
||||
|
||||
token = get_setting_value('PUSHSAFER_TOKEN')
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] PUSHSAFER_TOKEN: "{hide_string(token)}"'])
|
||||
|
||||
|
||||
try:
|
||||
url = 'https://www.pushsafer.com/api'
|
||||
post_fields = {
|
||||
"t" : 'Pi.Alert Message',
|
||||
"m" : text,
|
||||
"s" : 11,
|
||||
"v" : 3,
|
||||
"i" : 148,
|
||||
"c" : '#ef7f7f',
|
||||
"d" : 'a',
|
||||
"u" : get_setting_value('REPORT_DASHBOARD_URL'),
|
||||
"ut" : 'Open Pi.Alert',
|
||||
"k" : token,
|
||||
}
|
||||
response = requests.post(url, data=post_fields)
|
||||
|
||||
response_status_code = response.status_code
|
||||
|
||||
|
||||
# Check if the request was successful (status code 200)
|
||||
if response_status_code == 200:
|
||||
response_text = response.text # This captures the response body/message
|
||||
else:
|
||||
response_text = json.dumps(response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: ', e])
|
||||
|
||||
response_text = e
|
||||
|
||||
return response_text, response_status_code
|
||||
|
||||
|
||||
return response_text, response_status_code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config():
|
||||
if get_setting_value('PUSHSAFER_TOKEN') == 'ApiKey':
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
# -------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
8
front/plugins/_publisher_webhook/README.md
Executable file
8
front/plugins/_publisher_webhook/README.md
Executable file
@@ -0,0 +1,8 @@
|
||||
## Overview
|
||||
|
||||
A plugin to publish a notification via the Webhook gateway. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or <a href="https://n8n.io/" target="_blank">n8n</a> to name a few. Check out this simple <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md" target="_blank">n8n guide here</a> to get started. If enabled, configure related settings below.
|
||||
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
409
front/plugins/_publisher_webhook/config.json
Executable file
409
front/plugins/_publisher_webhook/config.json
Executable file
@@ -0,0 +1,409 @@
|
||||
{
|
||||
"code_name": "_publisher_webhook",
|
||||
"unique_prefix": "WEBHOOK",
|
||||
"plugin_type": "publisher",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name" : [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Webhook publisher"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilitar Webhook"
|
||||
}
|
||||
],
|
||||
"icon":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "<i class=\"fa-solid fa-circle-nodes\"></i>"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "A plugin to publish a notification via Webhooks."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
],
|
||||
"database_column_definitions":
|
||||
[
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "N/A"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Sent when"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": true,
|
||||
"type": "eval",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"type": "eval",
|
||||
"param": "`<a href='/report.php?guid=${value}'>${value}</a>`"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Notification GUID"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response (stdout)"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response (stderr)"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value4",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "device_mac",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Device"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comentarios"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code": "en_us",
|
||||
"string" : "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Extra"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"settings":[
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["test"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "on_notification" ],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code": "en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Cuando ejecuta"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Enable webhooks for notifications. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or <a href=\"https://n8n.io/\" target=\"_blank\">n8n</a> to name a few. Check out this simple <a href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md\" target=\"_blank\">n8n guide here</a> to get started. If enabled, configure related settings below."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Habilite webhooks para notificaciones. Los webhooks lo ayudan a conectarse a muchas herramientas de terceros, como IFTTT, Zapier o <a href=\"https://n8n.io/\" target=\"_blank\">n8n</a>, por nombrar algunas. Consulte esta sencilla <a href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md\" target=\"_blank\">guía de n8n aquí</a> para obtener comenzó. Si está habilitado, configure los ajustes relacionados a continuación."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value":"python3 /home/pi/pialert/front/plugins/_publisher_webhook/webhook.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Comando a ejecutar"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string" : "Wartezeit"
|
||||
}],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "URL",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Target URL"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL de destino"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Target URL starting with <code>http://</code> or <code>https://</code>."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "URL de destino comienza con <code>http://</code> o <code>https://</code>."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "PAYLOAD",
|
||||
"type": "text.select",
|
||||
"default_value": "json",
|
||||
"options": ["json", "html", "text"],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Payload type"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tipo de carga"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "The Webhook payload data format for the <code>body</code> > <code>attachments</code> > <code>text</code> attribute in the payload json. See an example of the payload <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json\">here</a>. (e.g.: for discord use <code>text</code>)"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "El formato de datos de carga de Webhook para el atributo <code>body</code> > <code>attachments</code> > <code>text</code> en el json de carga. Vea un ejemplo de la carga <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json\">aquí</a>. (por ejemplo: para discord use <code>text</code>)"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "REQUEST_METHOD",
|
||||
"type": "text.select",
|
||||
"default_value": "GET",
|
||||
"options": ["GET", "POST", "PUT"],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Request method"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Método de solicitud"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "The HTTP request method to be used for the webhook call."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "El método de solicitud HTTP que se utilizará para la llamada de webhook."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "SIZE",
|
||||
"type": "integer",
|
||||
"default_value": 1024,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "Max payload size"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "Tamaño máximo de carga útil"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "The maximum size of the webhook payload as number of characters in the passed string. If above limit, it will be truncated and a <code>(text was truncated)</code> message is appended."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : "El tamaño máximo de la carga útil del webhook como número de caracteres en la cadena pasada. Si supera el límite, se truncará y se agregará un mensaje <code>(text was truncated)</code>."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "SECRET",
|
||||
"type": "text",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code": "en_us",
|
||||
"string" : "HMAC Secret"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string" : ""
|
||||
}],
|
||||
"description": [{
|
||||
"language_code": "en_us",
|
||||
"string" : "When set, use this secret to generate the SHA256-HMAC hex digest value of the request body, which will be passed as the <code>X-Webhook-Signature</code> header to the request. You can find more information <a target=\"_blank\" href=\"https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_SECRET.md\">here</a>."
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
190
front/plugins/_publisher_webhook/webhook.py
Executable file
190
front/plugins/_publisher_webhook/webhook.py
Executable file
@@ -0,0 +1,190 @@
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from base64 import b64encode
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
# pialert modules
|
||||
import conf
|
||||
from const import logPath
|
||||
from plugin_helper import Plugin_Objects, handleEmpty
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value, hide_string, write_file
|
||||
from notification import Notification_obj
|
||||
from database import DB
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
pluginName = 'WEBHOOK'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}](publisher) In script'])
|
||||
|
||||
# Check if basic config settings supplied
|
||||
if check_config() == False:
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.'])
|
||||
return
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Notification_obj instance
|
||||
notifications = Notification_obj(db)
|
||||
|
||||
# Retrieve new notifications
|
||||
new_notifications = notifications.getNew()
|
||||
|
||||
# Process the new notifications (see the Notifications DB table for structure or check the /api/table_notifications.json endpoint)
|
||||
for notification in new_notifications:
|
||||
|
||||
# Send notification
|
||||
response_stdout, response_stderr = send(notification["Text"], notification["HTML"], notification["JSON"])
|
||||
|
||||
# Log result
|
||||
plugin_objects.add_object(
|
||||
primaryId = pluginName,
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = notification["GUID"],
|
||||
watched2 = handleEmpty(response_stdout),
|
||||
watched3 = handleEmpty(response_stderr),
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = notification["GUID"]
|
||||
)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def check_config():
|
||||
if get_setting_value('WEBHOOK_URL') == '':
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def send (text_data, html_data, json_data):
|
||||
|
||||
response_stderr = ''
|
||||
response_stdout = ''
|
||||
|
||||
# limit = 1024 * 1024 # 1MB limit (1024 bytes * 1024 bytes = 1MB)
|
||||
limit = get_setting_value('WEBHOOK_SIZE')
|
||||
payloadType = get_setting_value('WEBHOOK_PAYLOAD')
|
||||
endpointUrl = get_setting_value('WEBHOOK_URL')
|
||||
secret = get_setting_value('WEBHOOK_SECRET')
|
||||
requestMethod = get_setting_value('WEBHOOK_REQUEST_METHOD')
|
||||
|
||||
# use data type based on specified payload type
|
||||
if payloadType == 'json':
|
||||
# In this code, the truncate_json function is used to recursively traverse the JSON object
|
||||
# and remove nodes that exceed the size limit. It checks the size of each node's JSON representation
|
||||
# using json.dumps and includes only the nodes that are within the limit.
|
||||
json_str = json.dumps(json_data)
|
||||
|
||||
if len(json_str) <= limit:
|
||||
payloadData = json_data
|
||||
else:
|
||||
def truncate_json(obj):
|
||||
if isinstance(obj, dict):
|
||||
return {
|
||||
key: truncate_json(value)
|
||||
for key, value in obj.items()
|
||||
if len(json.dumps(value)) <= limit
|
||||
}
|
||||
elif isinstance(obj, list):
|
||||
return [
|
||||
truncate_json(item)
|
||||
for item in obj
|
||||
if len(json.dumps(item)) <= limit
|
||||
]
|
||||
else:
|
||||
return obj
|
||||
|
||||
payloadData = truncate_json(json_data)
|
||||
if payloadType == 'html':
|
||||
if len(html_data) > limit:
|
||||
payloadData = html_data[:limit] + " <h1>(text was truncated)</h1>"
|
||||
else:
|
||||
payloadData = html_data
|
||||
if payloadType == 'text':
|
||||
if len(text_data) > limit:
|
||||
payloadData = text_data[:limit] + " (text was truncated)"
|
||||
else:
|
||||
payloadData = text_data
|
||||
|
||||
# Define slack-compatible payload
|
||||
_json_payload = { "text": payloadData } if payloadType == 'text' else {
|
||||
"username": "Pi.Alert",
|
||||
"text": "There are new notifications",
|
||||
"attachments": [{
|
||||
"title": "Pi.Alert Notifications",
|
||||
"title_link": get_setting_value('REPORT_DASHBOARD_URL'),
|
||||
"text": payloadData
|
||||
}]
|
||||
}
|
||||
|
||||
# DEBUG - Write the json payload into a log file for debugging
|
||||
write_file (logPath + '/webhook_payload.json', json.dumps(_json_payload))
|
||||
|
||||
# Using the Slack-Compatible Webhook endpoint for Discord so that the same payload can be used for both
|
||||
# Consider: curl has the ability to load in data to POST from a file + piping
|
||||
if(endpointUrl.startswith('https://discord.com/api/webhooks/') and not endpointUrl.endswith("/slack")):
|
||||
_WEBHOOK_URL = f"{endpointUrl}/slack"
|
||||
curlParams = ["curl","-i","-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), _WEBHOOK_URL]
|
||||
else:
|
||||
_WEBHOOK_URL = endpointUrl
|
||||
curlParams = ["curl","-i","-X", requestMethod , "-H", "Content-Type:application/json", "-d", json.dumps(_json_payload), _WEBHOOK_URL]
|
||||
|
||||
# Add HMAC signature if configured
|
||||
if(secret != ''):
|
||||
h = hmac.new(secret.encode("UTF-8"), json.dumps(_json_payload, separators=(',', ':')).encode(), hashlib.sha256).hexdigest()
|
||||
curlParams.insert(4,"-H")
|
||||
curlParams.insert(5,f"X-Webhook-Signature: sha256={h}")
|
||||
|
||||
try:
|
||||
# Execute CURL call
|
||||
mylog('debug', [f'[{pluginName}] curlParams: ', curlParams])
|
||||
result = subprocess.run(curlParams, capture_output=True, text=True)
|
||||
|
||||
response_stderr = result.stderr
|
||||
response_stdout = result.stdout
|
||||
|
||||
# Write stdout and stderr into .log files for debugging if needed
|
||||
mylog('debug', [f'[{pluginName}] stdout: ', response_stdout])
|
||||
mylog('debug', [f'[{pluginName}] stderr: ', response_stderr])
|
||||
|
||||
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occurred, handle it
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: ', e.output])
|
||||
|
||||
response_stderr = e.output
|
||||
|
||||
|
||||
return response_stdout, response_stderr
|
||||
|
||||
# -------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
12
front/plugins/arp_scan/README_DE.md
Executable file
12
front/plugins/arp_scan/README_DE.md
Executable file
@@ -0,0 +1,12 @@
|
||||
## Übersicht
|
||||
|
||||
ARP-Scan ist ein Kommandozeilen-Werkzeug, welches das ARP-Protokoll nutzt, um IP-Hosts im lokalen Netzwerk zu erkennen und identifizieren. Eine Alternative zum ARP-Scan ist die Aktivierung der PiHole-Integration (`PIHOLE_RUN`) in den Einstellungen. Die Dauer des ARP-Scan (und andere Netzwerkscan-Plugins, welche die `SCAN_SUBNETS`-Einstellung nutzen) ist abhängig von der Anzahl der zu prüfenden IP-Adressen. Daher ist es wichtig, dies mit größter Vorsicht und den korrekten Netzwerkmasken und -interfaces zu konfigurieren. Die [Subnetz-Dokumentation](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md) ansehen für mehr Hilfe zum Aufsetzen von VLANs, welche VLANs unterstützt werden und zum Herausfinden der Netzwerkmaske und -interfaces.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Zur Einstellungen-Seite gehen und die `SCAN_SUBNETS`-Einstellung anhand der [Subnetz-Dokumentation](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md) konfigurieren
|
||||
- Das Plugin aktivieren, indem der `RUN`-Parameter von `disabled` auf den gewünschten Ausführzeitpunkt gesetzt wird (normalerweise: `schedule`)
|
||||
- Zeitplan in der `ARPSCAN_RUN_SCHD`-Einstellung setzen
|
||||
- Zeitlimit nach Bedarf in der `ARPSCAN_RUN_TIMEOUT`-Einstellung setzen
|
||||
- SPEICHERN
|
||||
- Auf Ausführung des nächsten Scans warten
|
||||
@@ -1,21 +1,25 @@
|
||||
{
|
||||
"code_name": "arp_scan",
|
||||
"unique_prefix": "ARPSCAN",
|
||||
"plugin_type": "device_scanner",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"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
|
||||
"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"],
|
||||
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -24,7 +28,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Arp-Scan (Escaneo de red)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "ARP-Scan (Netzwerkscan)"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
@@ -34,7 +42,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-search\"></i>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-search\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -44,48 +56,77 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Este plugin es para ejecutar un escaneo arp en la red local."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
},
|
||||
{
|
||||
"name" : "subnets",
|
||||
"type" : "setting",
|
||||
"value" : "SCAN_SUBNETS",
|
||||
"base64": true
|
||||
}],
|
||||
|
||||
"language_code": "de_de",
|
||||
"string": "Dieses Plugin wird genutzt, um einen ARP-Scan auf dem lokalen Netzwerk durchzuführen"
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "subnets",
|
||||
"type": "setting",
|
||||
"value": "SCAN_SUBNETS",
|
||||
"base64": true
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"type": "text.select",
|
||||
"default_value":"schedule",
|
||||
"options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
|
||||
"localized": ["name", "description"],
|
||||
"events": ["run"],
|
||||
"name" :[
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuando ejecutar"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Specify when your Network-discovery scan will run. Typical setting would be <code>schedule</code> and then you specify a cron-like schedule in the <a href=\"#ARPSCAN_RUN_SCHD\"><code>ARPSCAN_RUN_SCHD</code>setting</a> "
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Especifique cuándo se ejecutará su análisis de descubrimiento de red. La configuración típica sería <code>schedule</code> y luego se especifica una programación similar a cron en la configuración <a href=\"#ARPSCAN_RUN_SCHD\"><code>ARPSCAN_RUN_SCHD</code></a> "
|
||||
}]
|
||||
},
|
||||
"function": "RUN",
|
||||
"type": "text.select",
|
||||
"default_value": "schedule",
|
||||
"options": [
|
||||
"disabled",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan",
|
||||
"on_new_device"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuando ejecutar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Specify when your Network-discovery scan will run. Typical setting would be <code>schedule</code> and then you specify a cron-like schedule in the <a href=\"#ARPSCAN_RUN_SCHD\"><code>ARPSCAN_RUN_SCHD</code>setting</a> "
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Especifique cuándo se ejecutará su análisis de descubrimiento de red. La configuración típica sería <code>schedule</code> y luego se especifica una programación similar a cron en la configuración <a href=\"#ARPSCAN_RUN_SCHD\"><code>ARPSCAN_RUN_SCHD</code></a> "
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Auswählen wann der Netzwerkscan laufen soll. Typischerweise wird <code>schedule</code> ausgewählt und ein cron-Intervall in der <a href=\"#ARPSCAN_RUN_SCHD\"><code>ARPSCAN_RUN_SCHD</code>Einstellung</a> gesetzt."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/arp_scan/script.py userSubnets={subnets}",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -94,7 +135,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -104,16 +149,22 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando para ejecutar. Esto no debe ser cambiado"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Auszuführender Befehl. Dieser sollte nicht geändert werden"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 300,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -122,7 +173,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitlimit"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -132,70 +187,126 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, se cancela el script."
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value":"*/3 * * * *",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Schedule"
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value": "*/5 * * * *",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Schedule"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#ARPSCAN_RUN\"><code>ARPSCAN_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>*/3 * * * *</code> will run the scan every 3 minutes. Will be run NEXT time the time passes. <br/> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices."
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#ARPSCAN_RUN\"><code>ARPSCAN_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>*/3 * * * *</code> ejecutará el escaneo cada 3 minutos. Se ejecutará la PRÓXIMA vez que pase el tiempo. <br/> Se recomienda utilizar el mismo intervalo de programación para todos los complementos que analizan su red."
|
||||
}]
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitplan"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#ARPSCAN_RUN\"><code>ARPSCAN_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>*/3 * * * *</code> will run the scan every 3 minutes. Will be run NEXT time the time passes. <br/> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#ARPSCAN_RUN\"><code>ARPSCAN_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>*/3 * * * *</code> ejecutará el escaneo cada 3 minutos. Se ejecutará la PRÓXIMA vez que pase el tiempo. <br/> Se recomienda utilizar el mismo intervalo de programación para todos los complementos que analizan su red."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiv, wenn <code>schedule</code> in der <a href=\"#ARPSCAN_RUN\"><code>ARPSCAN_RUN</code> Einstellung</a> ausgewählt wurde. Sichergehen, dass das Intervall in einem korrekten cron-ähnlichen Format angegeben wurde (z.B. auf <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a> testen). <code>*/3 * * * *</code> würde den Scan alle 3 Minuten starten. Wird erst beim NÄCHSTEN Intervall ausgeführt. <br/>Es wird empfohlen, das Intervall aller Plugins, welche nach neuen Geräten suchen, auf den gleichen Wert zu setzen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "WATCH",
|
||||
"type": "text.multiselect",
|
||||
"default_value":["Watched_Value1", "Watched_Value2"],
|
||||
"options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Watched"
|
||||
"function": "WATCH",
|
||||
"type": "text.multiselect",
|
||||
"default_value": [
|
||||
"Watched_Value1",
|
||||
"Watched_Value2"
|
||||
],
|
||||
"options": [
|
||||
"Watched_Value1",
|
||||
"Watched_Value2",
|
||||
"Watched_Value3",
|
||||
"Watched_Value4"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Watched"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Watched"
|
||||
}] ,
|
||||
"description":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is IP</li><li><code>Watched_Value2</code> is Vendor</li><li><code>Watched_Value3</code> is Interface </li><li><code>Watched_Value4</code> is N/A </li></ul>"
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Watched"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Envía una notificación si los valores seleccionados cambian. Utilice <code>CTRL + clic</code> para seleccionar/deseleccionar. <ul> <li><code>Valor_observado1</code> es IP</li><li><code>Valor_observado2</code> es Proveedor</li><li><code>Valor_observado3</code> es Interfaz </li><li><code>Valor_observado4</code> es N/A </li></ul>"
|
||||
}]
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is IP</li><li><code>Watched_Value2</code> is Vendor</li><li><code>Watched_Value3</code> is Interface </li><li><code>Watched_Value4</code> is N/A </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Envía una notificación si los valores seleccionados cambian. Utilice <code>CTRL + clic</code> para seleccionar/deseleccionar. <ul> <li><code>Valor_observado1</code> es IP</li><li><code>Valor_observado2</code> es Proveedor</li><li><code>Valor_observado3</code> es Interfaz </li><li><code>Valor_observado4</code> es N/A </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Sende eine Benachrichtigung, wenn ein ausgwählter Wert sich ändert. <code>STRG + klicken</code> zum aus-/abwählen. <ul> <li><code>Watched_Value1</code> ist die IP</li><li><code>Watched_Value2</code> ist der Hersteller</li><li><code>Watched_Value3</code> ist das Interface </li><li><code>Watched_Value4</code> ist nicht in Verwendung </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "text.multiselect",
|
||||
"default_value": ["new"],
|
||||
"options": ["new", "watched-changed", "watched-not-changed", "missing-in-last-scan"],
|
||||
"localized": ["name", "description"],
|
||||
"default_value": [
|
||||
"new"
|
||||
],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Report on"
|
||||
},
|
||||
{
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -205,157 +316,235 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuándo debe enviarse una notificación."
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann Benachrichtigungen gesendet werden sollen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "ARGS",
|
||||
"type": "text",
|
||||
"default_value": "sudo arp-scan --ignoredups --retry=6",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Arguments"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Arguments to run arps-scan with. Recommended and tested only with the setting: <br/> <code>sudo arp-scan --ignoredups --retry=6</code>."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"database_column_definitions":
|
||||
[
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"mapped_to_column": "cur_MAC",
|
||||
"mapped_to_column": "cur_MAC",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_name_mac",
|
||||
"default_value":"",
|
||||
"type": "device_name_mac",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "MAC"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "MAC"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "IP"
|
||||
}]
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Proveedor"
|
||||
}]
|
||||
} ,
|
||||
{
|
||||
"column": "Dummy",
|
||||
"mapped_to_column": "cur_ScanMethod",
|
||||
"mapped_to_column_data": {
|
||||
"value": "arp-scan"
|
||||
},
|
||||
"column": "Watched_Value1",
|
||||
"mapped_to_column": "cur_IP",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "device_ip",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Scan method"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Método de escaneo"
|
||||
}]
|
||||
} ,
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Proveedor"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Hersteller"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Dummy",
|
||||
"mapped_to_column": "cur_ScanMethod",
|
||||
"mapped_to_column_data": {
|
||||
"value": "arp-scan"
|
||||
},
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Scan method"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Método de escaneo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Scanmethode"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Created"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Creado"
|
||||
}]
|
||||
},
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Created"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Erstellt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "Changed"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cambiado"
|
||||
}
|
||||
]
|
||||
},
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
}
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,11 @@ from time import strftime
|
||||
sys.path.append("/home/pi/pialert/front/plugins")
|
||||
sys.path.append('/home/pi/pialert/pialert')
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects
|
||||
# pialert modules
|
||||
from database import DB
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, handleEmpty
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from const import logPath, pialertPath
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
@@ -62,6 +64,11 @@ def main():
|
||||
subnets_list = userSubnetsParam.split(',')
|
||||
else:
|
||||
subnets_list = [userSubnetsParam]
|
||||
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Execute the ARP scanning process on the list of subnets (whether it's one or multiple subnets).
|
||||
# The function 'execute_arpscan' is assumed to be defined elsewhere in the code.
|
||||
@@ -70,14 +77,14 @@ def main():
|
||||
|
||||
for device in unique_devices:
|
||||
plugin_objects.add_object(
|
||||
primaryId=device['mac'], # MAC (Device Name)
|
||||
secondaryId=device['ip'], # IP Address
|
||||
watched1=device['ip'], # Device Name
|
||||
watched2=device.get('hw', ''), # Vendor (assuming it's in the 'hw' field)
|
||||
watched3=device.get('interface', ''), # Add the interface
|
||||
watched4='',
|
||||
extra='arp-scan',
|
||||
foreignKey="")
|
||||
primaryId = handleEmpty(device['mac']), # MAC (Device Name)
|
||||
secondaryId = handleEmpty(device['ip']), # IP Address
|
||||
watched1 = handleEmpty(device['ip']), # Device Name
|
||||
watched2 = handleEmpty(device.get('hw', '')), # Vendor (assuming it's in the 'hw' field)
|
||||
watched3 = handleEmpty(device.get('interface', '')), # Add the interface
|
||||
watched4 = '',
|
||||
extra = 'arp-scan',
|
||||
foreignKey = "")
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
@@ -132,7 +139,7 @@ def execute_arpscan(userSubnets):
|
||||
|
||||
def execute_arpscan_on_interface(interface):
|
||||
# Prepare command arguments
|
||||
arpscan_args = ['sudo', 'arp-scan', '--ignoredups', '--retry=6'] + interface.split()
|
||||
arpscan_args = get_setting_value('ARPSCAN_ARGS').split() + interface.split()
|
||||
|
||||
# Execute command
|
||||
try:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "csv_backup",
|
||||
"unique_prefix": "CSVBCKP",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": false,
|
||||
@@ -24,15 +25,7 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-save\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-save\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-save\"></i>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "db_cleanup",
|
||||
"unique_prefix": "DBCLNP",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# test script by running:
|
||||
# /home/pi/pialert/front/plugins/db_cleanup/script.py pluginskeephistory=250 hourstokeepnewdevice=48 daystokeepevents=90
|
||||
# /home/pi/pialert/front/plugins/db_cleanup/script.py pluginskeephistory=250 hourstokeepnewdevice=48 daystokeepevents=90 pholuskeepdays=30
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
@@ -17,7 +17,7 @@ sys.path.append('/home/pi/pialert/pialert')
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from const import logPath, pialertPath
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ def main():
|
||||
|
||||
values = parser.parse_args()
|
||||
|
||||
PLUGINS_KEEP_HIST = values.pluginskeephistory.split('=')[1]
|
||||
HRS_TO_KEEP_NEWDEV = values.hourstokeepnewdevice.split('=')[1]
|
||||
DAYS_TO_KEEP_EVENTS = values.daystokeepevents.split('=')[1]
|
||||
PHOLUS_DAYS_DATA = values.pholuskeepdays.split('=')[1]
|
||||
PLUGINS_KEEP_HIST = int(values.pluginskeephistory.split('=')[1])
|
||||
HRS_TO_KEEP_NEWDEV = int(values.hourstokeepnewdevice.split('=')[1])
|
||||
DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1])
|
||||
PHOLUS_DAYS_DATA = int(values.pholuskeepdays.split('=')[1])
|
||||
|
||||
mylog('verbose', ['[DBCLNP] In script'])
|
||||
|
||||
@@ -92,6 +92,27 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
||||
|
||||
cursor.execute(delete_query)
|
||||
|
||||
|
||||
# Trim Notifications entries to less than DBCLNP_NOTIFI_HIST setting
|
||||
|
||||
histCount = get_setting_value('DBCLNP_NOTIFI_HIST')
|
||||
|
||||
mylog('verbose', [f'[DBCLNP] Plugins_History: Trim Notifications entries to less than {histCount}'])
|
||||
|
||||
# Build the SQL query to delete entries
|
||||
delete_query = f"""DELETE FROM Notifications
|
||||
WHERE "Index" NOT IN (
|
||||
SELECT "Index"
|
||||
FROM (
|
||||
SELECT "Index",
|
||||
ROW_NUMBER() OVER(PARTITION BY "Notifications" ORDER BY DateTimeCreated DESC) AS row_num
|
||||
FROM Notifications
|
||||
) AS ranked_objects
|
||||
WHERE row_num <= {histCount}
|
||||
);"""
|
||||
|
||||
cursor.execute(delete_query)
|
||||
|
||||
# Cleanup Pholus_Scan
|
||||
if PHOLUS_DAYS_DATA != 0:
|
||||
mylog('verbose', ['[DBCLNP] Pholus_Scan: Delete all older than ' + str(PHOLUS_DAYS_DATA) + ' days (PHOLUS_DAYS_DATA setting)'])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Overview
|
||||
|
||||
Plugin to run regular DDNS update tasks.
|
||||
Plugin to run regular DDNS update tasks.
|
||||
|
||||
### Usage
|
||||
|
||||
|
||||
7
front/plugins/ddns_update/README_DE.md
Executable file
7
front/plugins/ddns_update/README_DE.md
Executable file
@@ -0,0 +1,7 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zur regelmäßigen Aktualisierung eines DynDNS-Eintrags.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Einstellungen-Seite für Details ansehen.
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"code_name": "ddns_update",
|
||||
"unique_prefix": "DDNS",
|
||||
"enabled": true,
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_filters": [
|
||||
{
|
||||
"compare_column": "Object_PrimaryID",
|
||||
@@ -22,18 +23,30 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "DDNS update"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DDNS-Aktualisierung"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-globe\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-globe\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin update the DDNS record."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Ein Plugin zur regelmäßigen Aktualisierung eines DynDNS-Eintrags."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
@@ -66,9 +79,11 @@
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "schedule",
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"once",
|
||||
@@ -90,13 +105,17 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann laufen"
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When the plugin should run. An hourly or daily <code>SCHEDULE</code> is a good option."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann das Plugin ausgeführt werden soll. Eine stündliche oder tägliche <code>SCHEDULE</code> wird empfohlen."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -158,7 +177,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Schedule"
|
||||
"string": "Zeitplan"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -172,7 +191,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#DDNS_RUN\"><code>DDNS_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
"string": "Nur aktiv, wenn <code>schedule</code> in der <a href=\"#DDNS_RUN\"><code>DDNS_RUN</code> Einstellung</a> ausgewählt wurde. Sichergehen, dass das Intervall in einem korrekten cron-ähnlichen Format angegeben wurde (z.B. auf <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a> testen). <code>0 4 * * *</code> würde den Scan täglich um 4 Uhr in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\">oben ausgewählten <code>TIMEZONE</code></a> starten. Wird erst beim NÄCHSTEN Intervall ausgeführt."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -196,7 +215,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitüberschreitung"
|
||||
"string": "Zeitlimit"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -231,6 +250,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "URL del dominio DynDNS"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DynDNS Domain URL"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -241,6 +264,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "URL del host DynDNS (no incluya http:// o https://)."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DynDNS Host URL (do not include http:// or https://)."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -261,6 +288,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Usuario de DynDNS"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DynDNS Benutzer"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -271,6 +302,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "El nombre de usuario utilizado para iniciar sesión en el servicio DynDNS (a veces, una dirección de correo electrónico completa)."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benutzername, welcher zum Login beim DynDNS-Service verwendet wird (manchmal die E-Mail-Adresse)."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -291,6 +326,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Contraseña de DynDNS"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DynDNS Passwort"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -301,6 +340,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "La contraseña de acceso al servicio DynDNS."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Passwort, welches zum Login beim DynDNS-Service verwendet wird."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -321,6 +364,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "URL de actualización de DynDNS"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "DynDNS Aktualisierungs-URL"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -331,6 +378,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Actualice la URL que comienza con <code>http://</code> o <code>https://</code>."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Aktualisierungs-URL beginnend mit <code>http://</code> oder <code>https://</code>."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -358,42 +409,73 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Visto"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Previous IP (not recommended)</li><li><code>Watched_Value2</code> unused</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Sende eine Benachrichtigung, wenn ein ausgwählter Wert sich ändert. <code>STRG + klicken</code> zum aus-/abwählen. <ul> <li><code>Watched_Value1</code> ist die Vorige IP (nicht empfohlen)</li><li><code>Watched_Value2</code> ist nicht in Verwendung</li><li><code>Watched_Value3</code> ist nicht in Verwendung </li><li><code>Watched_Value4</code> ist nicht in Verwendung </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "text.multiselect",
|
||||
"default_value":["new","watched-changed"],
|
||||
"options": ["new","watched-changed","watched-not-changed", "missing-in-last-scan"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Report on"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Informar sobre"
|
||||
} ] ,
|
||||
"description":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (una combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que las columnas <code>Watched_ValueN</code> seleccionadas cambiaron."
|
||||
}]
|
||||
}
|
||||
"default_value": [
|
||||
"new",
|
||||
"watched-changed"
|
||||
],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Report on"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (una combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que las columnas <code>Watched_ValueN</code> seleccionadas cambiaron."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige nur bei diesen Status. <code>new</code> bedeutet ein neues eindeutiges (einzigartige Kombination aus PrimaryId und SecondaryId) Objekt wurde erkennt. <code>watched-changed</code> bedeutet eine ausgewählte <code>Watched_ValueN</code>-Spalte hat sich geändert."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_name_mac",
|
||||
@@ -410,11 +492,15 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_ip",
|
||||
@@ -431,6 +517,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -448,11 +538,15 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Extra"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Dummy",
|
||||
"column": "Dummy",
|
||||
"mapped_to_column_data": {
|
||||
"value": "DDNS"
|
||||
},
|
||||
@@ -472,6 +566,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Método de escaneo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Scanmethode"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -493,11 +591,15 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Erstellt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
@@ -514,6 +616,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -552,6 +658,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -28,9 +28,11 @@ 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')
|
||||
|
||||
pluginName = 'DDNS'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', ['[DDNS] In script'])
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
parser = argparse.ArgumentParser(description='Check internet connectivity and IP')
|
||||
|
||||
@@ -52,7 +54,7 @@ def main():
|
||||
# perform the new IP lookup and DDNS tasks if enabled
|
||||
ddns_update( DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN, PREV_IP)
|
||||
|
||||
mylog('verbose', ['[DDNS] Finished '])
|
||||
mylog('verbose', [f'[{pluginName}] Finished '])
|
||||
|
||||
return 0
|
||||
|
||||
@@ -65,20 +67,20 @@ def ddns_update ( DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN, PREV_I
|
||||
# Update DDNS record if enabled and IP is different
|
||||
# Get Dynamic DNS IP
|
||||
|
||||
mylog('verbose', ['[DDNS] Retrieving Dynamic DNS IP'])
|
||||
mylog('verbose', [f'[{pluginName}] Retrieving Dynamic DNS IP'])
|
||||
dns_IP = get_dynamic_DNS_IP(DDNS_DOMAIN)
|
||||
|
||||
# Check Dynamic DNS IP
|
||||
if dns_IP == "" or dns_IP == "0.0.0.0" :
|
||||
mylog('none', ['[DDNS] Error retrieving Dynamic DNS IP'])
|
||||
mylog('none', [f'[{pluginName}] Error retrieving Dynamic DNS IP'])
|
||||
|
||||
mylog('none', ['[DDNS] ', dns_IP])
|
||||
mylog('none', [f'[{pluginName}] ', dns_IP])
|
||||
|
||||
# Check DNS Change
|
||||
if dns_IP != PREV_IP :
|
||||
mylog('none', ['[DDNS] Updating Dynamic DNS IP'])
|
||||
mylog('none', [f'[{pluginName}] Updating Dynamic DNS IP'])
|
||||
message = set_dynamic_DNS_IP (DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN)
|
||||
mylog('none', ['[DDNS] ', message])
|
||||
mylog('none', [f'[{pluginName}] ', message])
|
||||
|
||||
# plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
@@ -104,9 +106,10 @@ def get_dynamic_DNS_IP (DDNS_DOMAIN):
|
||||
try:
|
||||
# try runnning a subprocess
|
||||
dig_output = subprocess.check_output (dig_args, universal_newlines=True)
|
||||
mylog('none', [f'[{pluginName}] DIG output :', dig_output])
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occured, handle it
|
||||
mylog('none', ['[DDNS] ERROR - ', e.output])
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR - ', e.output])
|
||||
dig_output = '' # probably no internet
|
||||
|
||||
# Check result is an IP
|
||||
@@ -132,7 +135,7 @@ def set_dynamic_DNS_IP (DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN):
|
||||
universal_newlines=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occured, handle it
|
||||
mylog('none', ['[DDNS] ERROR - ',e.output])
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR - ',e.output])
|
||||
curl_output = ""
|
||||
|
||||
return curl_output
|
||||
|
||||
51
front/plugins/dhcp_leases/README_DE.md
Executable file
51
front/plugins/dhcp_leases/README_DE.md
Executable file
@@ -0,0 +1,51 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zum Importieren von Geräten aus dhcp.leases-Dateien.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Absolute Pfade der `dhcp.leases`-Dateien, welche importiert werden sollen, in der `DHCPLSS_paths_to_check`-Einstellung angeben.
|
||||
- Angegebene Pfade in der `DHCPLSS_paths_to_check`-Einstellung in der `docker-compose.yml`-Datei mapppen.
|
||||
|
||||
#### Beispiel
|
||||
|
||||
Auszug aus `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
...
|
||||
# mapping different dhcp.leases files
|
||||
- /first/location/dhcp.leases:/mnt/dhcp1.leases
|
||||
- /second/location/dhcp.leases:/mnt/dhcp2.leases
|
||||
...
|
||||
```
|
||||
|
||||
`DHCPLSS_paths_to_check`-Einstellung:
|
||||
|
||||
```python
|
||||
DHCPLSS_paths_to_check = ['/mnt/dhcp1.leases','/mnt/dhcp2.leases']
|
||||
```
|
||||
|
||||
### Notizen
|
||||
|
||||
- Keine spezifische Konfiguration benötigt.
|
||||
|
||||
- Dieses Plugin erwartet dhcp.leases-Dateien im **dhcp.leases**-Format, welches sich vom von PiHole genutzten Format unterscheidet. [dhcpd.leases(5) - Linux man page]( https://linux.die.net/man/5/dhcpd.leases#:~:text=This%20database%20is%20a%20free,file%20is%20the%20current%20one.)
|
||||
|
||||
Beispiel Dateiformat: _(nicht alle Zeilen werden benötigt)_
|
||||
|
||||
```text
|
||||
lease 192.168.79.15 {
|
||||
starts 0 2016/08/21 13:25:45;
|
||||
ends 0 2016/08/21 19:25:45;
|
||||
cltt 0 2016/08/21 13:25:45;
|
||||
binding state active;
|
||||
next binding state free;
|
||||
rewind binding state free;
|
||||
hardware ethernet 8c:1a:bf:11:00:ea;
|
||||
uid "\001\214\032\277\021\000\352";
|
||||
option agent.circuit-id 0:17;
|
||||
option agent.remote-id c0:a8:9:5;
|
||||
client-hostname "android-8182e21c852776e7";
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import chardet
|
||||
|
||||
sys.path.append("/home/pi/pialert/front/plugins")
|
||||
sys.path.append('/home/pi/pialert/pialert')
|
||||
@@ -18,8 +19,12 @@ 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')
|
||||
|
||||
|
||||
pluginName= 'DHCPLSS'
|
||||
|
||||
# -------------------------------------------------------------
|
||||
def main():
|
||||
mylog('verbose', ['[DHCPLSS] In script'])
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
last_run_logfile = open(RESULT_FILE, 'a')
|
||||
last_run_logfile.write("")
|
||||
|
||||
@@ -32,42 +37,55 @@ def main():
|
||||
if values.paths:
|
||||
for path in values.paths.split('=')[1].split(','):
|
||||
plugin_objects = get_entries(path, plugin_objects)
|
||||
mylog('verbose', [f'[DHCPLSS] {len(plugin_objects)} Entries found in "{path}"'])
|
||||
mylog('verbose', [f'[{pluginName}] {len(plugin_objects)} Entries found in "{path}"'])
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
# -------------------------------------------------------------
|
||||
def get_entries(path, plugin_objects):
|
||||
if 'pihole' in path:
|
||||
|
||||
|
||||
with open(path, 'r') as f:
|
||||
for line in f:
|
||||
row = line.rstrip().split()
|
||||
if len(row) == 5:
|
||||
plugin_objects.add_object(
|
||||
primaryId = handleEmpty(row[1]),
|
||||
secondaryId = handleEmpty(row[2]),
|
||||
watched1 = handleEmpty('True'),
|
||||
watched2 = handleEmpty(row[3]),
|
||||
watched3 = handleEmpty(row[4]),
|
||||
watched4 = handleEmpty('True'),
|
||||
extra = handleEmpty(path),
|
||||
foreignKey = handleEmpty(row[1])
|
||||
)
|
||||
|
||||
# Check if the path exists
|
||||
if not os.path.exists(path):
|
||||
mylog('none', [f'[{pluginName}] ⚠ ERROR: "{path}" does not exist.'])
|
||||
else:
|
||||
leases = DhcpLeases(path)
|
||||
leasesList = leases.get()
|
||||
for lease in leasesList:
|
||||
plugin_objects.add_object(
|
||||
primaryId = handleEmpty(lease.ethernet),
|
||||
secondaryId = handleEmpty(lease.ip),
|
||||
watched1 = handleEmpty(lease.active),
|
||||
watched2 = handleEmpty(lease.hostname),
|
||||
watched3 = handleEmpty(lease.hardware),
|
||||
watched4 = handleEmpty(lease.binding_state),
|
||||
extra = handleEmpty(path),
|
||||
foreignKey = handleEmpty(lease.ethernet)
|
||||
)
|
||||
# Detect file encoding
|
||||
with open(path, 'rb') as f:
|
||||
result = chardet.detect(f.read())
|
||||
|
||||
# Use the detected encoding
|
||||
encoding = result['encoding']
|
||||
|
||||
# Handle pihole-specific dhcp.leases files
|
||||
if 'pihole' in path:
|
||||
with open(path, 'r', encoding=encoding, errors='replace') as f:
|
||||
for line in f:
|
||||
row = line.rstrip().split()
|
||||
if len(row) == 5:
|
||||
plugin_objects.add_object(
|
||||
primaryId = handleEmpty(row[1]),
|
||||
secondaryId = handleEmpty(row[2]),
|
||||
watched1 = handleEmpty('True'),
|
||||
watched2 = handleEmpty(row[3]),
|
||||
watched3 = handleEmpty(row[4]),
|
||||
watched4 = handleEmpty('True'),
|
||||
extra = handleEmpty(path),
|
||||
foreignKey = handleEmpty(row[1])
|
||||
)
|
||||
else:
|
||||
# Handle generic dhcp.leases files
|
||||
leases = DhcpLeases(path)
|
||||
leasesList = leases.get()
|
||||
for lease in leasesList:
|
||||
plugin_objects.add_object(
|
||||
primaryId = handleEmpty(lease.ethernet),
|
||||
secondaryId = handleEmpty(lease.ip),
|
||||
watched1 = handleEmpty(lease.active),
|
||||
watched2 = handleEmpty(lease.hostname),
|
||||
watched3 = handleEmpty(lease.hardware),
|
||||
watched4 = handleEmpty(lease.binding_state),
|
||||
extra = handleEmpty(path),
|
||||
foreignKey = handleEmpty(lease.ethernet)
|
||||
)
|
||||
return plugin_objects
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "dhcp_servers",
|
||||
"unique_prefix": "DHCPSRVS",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
@@ -345,7 +346,7 @@
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value":5,
|
||||
"default_value":10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
|
||||
7
front/plugins/internet_ip/README_DE.md
Executable file
7
front/plugins/internet_ip/README_DE.md
Executable file
@@ -0,0 +1,7 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zur regelmäßigen Prüfung der Internetverbindung und externen IP.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Einstellungen-Seite für Details ansehen.
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "internet_ip",
|
||||
"unique_prefix": "INTRNT",
|
||||
"plugin_type": "device_scanner",
|
||||
"enabled": true,
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"data_filters": [
|
||||
@@ -23,18 +24,30 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Internet check"
|
||||
},
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Internet-Check"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-globe\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-globe\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to check your internet connectivity and IP."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Ein Plugin zur Prüfung der Internetverbindung und externen IP."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
@@ -53,7 +66,9 @@
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "schedule",
|
||||
"options": [
|
||||
@@ -77,13 +92,17 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann laufen"
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When the plugin should run. An hourly or daily <code>SCHEDULE</code> is a good option."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann das Plugin ausgeführt werden soll. Eine stündliche oder tägliche <code>SCHEDULE</code> wird empfohlen."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -145,13 +164,13 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Schedule"
|
||||
"string": "Zeitplan"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#INTRNT_RUN\"><code>INTRNT_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#INTRNT_RUN\"><code>INTRNT_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes. It's recommended to use the same schedule interval for all plugins responsible for discovering new devices."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
@@ -159,7 +178,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#INTRNT_RUN\"><code>INTRNT_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
"string": "Nur aktiv, wenn <code>schedule</code> in der <a href=\"#INTRNT_RUN\"><code>INTRNT_RUN</code>Einstellung</a> ausgewählt wurde. Sichergehen, dass das Intervall in einem korrekten cron-ähnlichen Format angegeben wurde (z.B. auf <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a> testen). <code>0 4 * * *</code> würde den Scan täglich um 4 Uhr in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\">oben ausgewählten <code>TIMEZONE</code></a> starten. Wird erst beim NÄCHSTEN Intervall ausgeführt. <br/>Es wird empfohlen, das Intervall aller Plugins, welche nach neuen Geräten suchen, auf den gleichen Wert zu setzen."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -183,7 +202,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitüberschreitung"
|
||||
"string": "Zeitlimit"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -225,38 +244,69 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Visto"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Previous IP (not recommended)</li><li><code>Watched_Value2</code> unused</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Sende eine Benachrichtigung, wenn ein ausgwählter Wert sich ändert. <code>STRG + klicken</code> zum aus-/abwählen. <ul> <li><code>Watched_Value1</code> ist die Vorige IP (nicht empfohlen)</li><li><code>Watched_Value2</code> ist nicht in Verwendung</li><li><code>Watched_Value3</code> ist nicht in Verwendung </li><li><code>Watched_Value4</code> ist nicht in Verwendung </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "text.multiselect",
|
||||
"default_value":["new","watched-changed"],
|
||||
"options": ["new","watched-changed","watched-not-changed", "missing-in-last-scan"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Report on"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Informar sobre"
|
||||
} ] ,
|
||||
"description":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (una combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que las columnas <code>Watched_ValueN</code> seleccionadas cambiaron."
|
||||
}]
|
||||
}
|
||||
"default_value": [
|
||||
"new",
|
||||
"watched-changed"
|
||||
],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Report on"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (una combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que las columnas <code>Watched_ValueN</code> seleccionadas cambiaron."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige nur bei diesen Status. <code>new</code> bedeutet ein neues eindeutiges (einzigartige Kombination aus PrimaryId und SecondaryId) Objekt wurde erkennt. <code>watched-changed</code> bedeutet eine ausgewählte <code>Watched_ValueN</code>-Spalte hat sich geändert."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
@@ -278,6 +328,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -300,6 +354,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -317,6 +375,25 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Extra"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "textarea_readonly",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string" : "Response"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -342,6 +419,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Método de escaneo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Scanmethode"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -363,6 +444,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Erstellt"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -385,6 +470,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -423,6 +512,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -28,9 +28,11 @@ 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')
|
||||
|
||||
pluginName = 'INTRNT'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', ['[INTRNT] In script'])
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
parser = argparse.ArgumentParser(description='Check internet connectivity and IP')
|
||||
|
||||
@@ -42,15 +44,15 @@ def main():
|
||||
PREV_IP = values.prev_ip.split('=')[1]
|
||||
DIG_GET_IP_ARG = values.DIG_GET_IP_ARG.split('=b')[1] # byte64 encoded
|
||||
|
||||
mylog('verbose', ['[INTRNT] DIG_GET_IP_ARG: ', DIG_GET_IP_ARG])
|
||||
mylog('verbose', [f'[{pluginName}] DIG_GET_IP_ARG: ', DIG_GET_IP_ARG])
|
||||
|
||||
# Decode the base64-encoded value to get the actual value in ASCII format.
|
||||
DIG_GET_IP_ARG = base64.b64decode(DIG_GET_IP_ARG).decode('ascii')
|
||||
|
||||
mylog('verbose', [f'[INTRNT] DIG_GET_IP_ARG resolved: {DIG_GET_IP_ARG} '])
|
||||
mylog('verbose', [f'[{pluginName}] DIG_GET_IP_ARG resolved: {DIG_GET_IP_ARG} '])
|
||||
|
||||
# perform the new IP lookup
|
||||
new_internet_IP = check_internet_IP( PREV_IP, DIG_GET_IP_ARG)
|
||||
new_internet_IP, cmd_output = check_internet_IP( PREV_IP, DIG_GET_IP_ARG)
|
||||
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
@@ -58,7 +60,7 @@ def main():
|
||||
primaryId = 'Internet', # MAC (Device Name)
|
||||
secondaryId = new_internet_IP, # IP Address
|
||||
watched1 = f'Previous IP: {PREV_IP}',
|
||||
watched2 = '',
|
||||
watched2 = cmd_output.replace('\n',''),
|
||||
watched3 = '',
|
||||
watched4 = '',
|
||||
extra = f'Previous IP: {PREV_IP}',
|
||||
@@ -66,7 +68,7 @@ def main():
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
mylog('verbose', ['[INTRNT] Finished '])
|
||||
mylog('verbose', [f'[{pluginName}] Finished '])
|
||||
|
||||
return 0
|
||||
|
||||
@@ -77,10 +79,10 @@ def main():
|
||||
def check_internet_IP ( PREV_IP, DIG_GET_IP_ARG ):
|
||||
|
||||
# Get Internet IP
|
||||
mylog('verbose', ['[INTRNT] - Retrieving Internet IP'])
|
||||
internet_IP = get_internet_IP(DIG_GET_IP_ARG)
|
||||
mylog('verbose', [f'[{pluginName}] - Retrieving Internet IP'])
|
||||
internet_IP, cmd_output = get_internet_IP(DIG_GET_IP_ARG)
|
||||
|
||||
mylog('verbose', [f'[INTRNT] Current internet_IP : {internet_IP}'])
|
||||
mylog('verbose', [f'[{pluginName}] Current internet_IP : {internet_IP}'])
|
||||
|
||||
# Check previously stored IP
|
||||
previous_IP = '0.0.0.0'
|
||||
@@ -88,23 +90,26 @@ def check_internet_IP ( PREV_IP, DIG_GET_IP_ARG ):
|
||||
if PREV_IP is not None and len(PREV_IP) > 0 :
|
||||
previous_IP = PREV_IP
|
||||
|
||||
mylog('verbose', [f'[INTRNT] previous_IP : {previous_IP}'])
|
||||
mylog('verbose', [f'[{pluginName}] previous_IP : {previous_IP}'])
|
||||
|
||||
# logging
|
||||
append_line_to_file (logPath + '/IP_changes.log', '['+str(timeNowTZ()) +']\t'+ internet_IP +'\n')
|
||||
|
||||
return internet_IP
|
||||
return internet_IP, cmd_output
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
def get_internet_IP (DIG_GET_IP_ARG):
|
||||
|
||||
cmd_output = ''
|
||||
|
||||
# Using 'dig'
|
||||
dig_args = ['dig', '+short'] + DIG_GET_IP_ARG.strip().split()
|
||||
try:
|
||||
cmd_output = subprocess.check_output (dig_args, universal_newlines=True)
|
||||
mylog('verbose', [f'[{pluginName}] DIG result : {cmd_output}'])
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('none', [e.output])
|
||||
mylog('verbose', [e.output])
|
||||
cmd_output = '' # no internet
|
||||
|
||||
# Check result is an IP
|
||||
@@ -114,7 +119,7 @@ def get_internet_IP (DIG_GET_IP_ARG):
|
||||
if IP == '':
|
||||
IP = '0.0.0.0'
|
||||
|
||||
return IP
|
||||
return IP, cmd_output
|
||||
|
||||
#===============================================================================
|
||||
# BEGIN
|
||||
|
||||
11
front/plugins/internet_speedtest/README.md
Executable file
11
front/plugins/internet_speedtest/README.md
Executable file
@@ -0,0 +1,11 @@
|
||||
## Overview
|
||||
|
||||
A simple plugin allowing for executing regular internet speed tests.
|
||||
|
||||
### Usage
|
||||
|
||||
- N/A
|
||||
|
||||
### Notes
|
||||
|
||||
- N/A
|
||||
3
front/plugins/internet_speedtest/README_DE.md
Executable file
3
front/plugins/internet_speedtest/README_DE.md
Executable file
@@ -0,0 +1,3 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zur periodischen Durchführung von Internetgeschwindigkeitstests.
|
||||
646
front/plugins/internet_speedtest/config.json
Executable file
646
front/plugins/internet_speedtest/config.json
Executable file
@@ -0,0 +1,646 @@
|
||||
{
|
||||
"code_name": "internet_speedtest",
|
||||
"unique_prefix": "INTRSPD",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Internet speedtest"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Internetgeschwindigkeitstest"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-gauge-high\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-gauge-high\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to perform a scheduled internet speedtest."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Ein Plugin zur periodischen Durchführung von Internetgeschwindigkeitstests."
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Index",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Plugin",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "url",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Test run on"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Test durchgeführt am"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "threshold",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"maximum": 1,
|
||||
"hexColor": "#D33115"
|
||||
},
|
||||
{
|
||||
"maximum": 5,
|
||||
"hexColor": "#792D86"
|
||||
},
|
||||
{
|
||||
"maximum": 10,
|
||||
"hexColor": "#7D862D"
|
||||
},
|
||||
{
|
||||
"maximum": 100,
|
||||
"hexColor": "#05483C"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Download"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Download"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "threshold",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"maximum": 1,
|
||||
"hexColor": "#D33115"
|
||||
},
|
||||
{
|
||||
"maximum": 5,
|
||||
"hexColor": "#792D86"
|
||||
},
|
||||
{
|
||||
"maximum": 10,
|
||||
"hexColor": "#7D862D"
|
||||
},
|
||||
{
|
||||
"maximum": 100,
|
||||
"hexColor": "#05483C"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Upload"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Upload"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "UserData",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "textbox_save",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Comments"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comentarios"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Kommentare"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": false,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Extra",
|
||||
"css_classes": "col-sm-3",
|
||||
"show": false,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Extra"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Extra"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuando ejecuta"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Enable a regular internet speedtest. 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=\"#INTRSPD_RUN_TIMEOUT\"><code>INTRSPD_RUN_TIMEOUT</code> setting</a>."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Aktiviere periodische Internetgeschwindigkeitstests. Wenn <code>schedule</code> ausgewählt ist, werden die Einstellungen von unten genutzt. Bei <code>once</code> wird der Test nur einmal beim Start der Applikation (Container) für die unten in der <a href=\"#INTRSPD_RUN_TIMEOUT\"><code>INTRSPD_RUN_TIMEOUT</code> Einstellung</a> gesetzten Zeit durchgeführt."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/internet_speedtest/script.py",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Auszuführender Befehl"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value": "*/30 * * * *",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitplan"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#INTRSPD_RUN\"><code>INTRSPD_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#INTRSPD_RUN\"><code>INTRSPD_RUN</code></a>. Asegúrese de ingresar el schedule en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingrese <code >0 4 * * *</code> ejecutará el escaneo después de las 4 am en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> que configuró arriba </a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiv, wenn <code>schedule</code> in der <a href=\"#INTRSPD_RUN\"><code>INTRSPD_RUN</code> Einstellung</a> ausgewählt wurde. Sichergehen, dass das Intervall in einem korrekten cron-ähnlichen Format angegeben wurde (z.B. auf <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a> testen). <code>0 4 * * *</code> würde den Scan täglich um 4 Uhr in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\">oben ausgewählten <code>TIMEZONE</code></a> starten. Wird erst beim NÄCHSTEN Intervall ausgeführt. <br/>Es wird empfohlen, das Intervall aller Plugins, welche nach neuen Geräten suchen, auf den gleichen Wert zu setzen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 60,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo de espera de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitlimit"
|
||||
}
|
||||
],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "WATCH",
|
||||
"type": "text.multiselect",
|
||||
"default_value": [],
|
||||
"options": [
|
||||
"Watched_Value1",
|
||||
"Watched_Value2",
|
||||
"Watched_Value3",
|
||||
"Watched_Value4"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Watched"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Visto"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Download speed (not recommended)</li><li><code>Watched_Value2</code> is Upload speed (not recommended)</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Sende eine Benachrichtigung, wenn ein ausgwählter Wert sich ändert. <code>STRG + klicken</code> zum aus-/abwählen. <ul> <li><code>Watched_Value1</code> ist die Download-Geschwindigkeit (nicht empfohlen)</li><li><code>Watched_Value2</code> ist die Upload-Geschwindigkeit (nicht empfohlen)</li><li><code>Watched_Value3</code> ist nicht in Verwendung </li><li><code>Watched_Value4</code> ist nicht in Verwendung </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "text.multiselect",
|
||||
"default_value": [],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Report on"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification only on these statuses. <code>new</code> means a new unique (unique combination of PrimaryId and SecondaryId) object was discovered. <code>watched-changed</code> means that selected <code>Watched_ValueN</code> columns changed."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que seleccionó <code>Watched_ValueN Las columnas </code> cambiaron."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige nur bei diesen Status. <code>new</code> bedeutet ein neues eindeutiges (einzigartige Kombination aus PrimaryId und SecondaryId) Objekt wurde erkennt. <code>watched-changed</code> bedeutet eine ausgewählte <code>Watched_ValueN</code>-Spalte hat sich geändert."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
60
front/plugins/internet_speedtest/script.py
Executable file
60
front/plugins/internet_speedtest/script.py
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from datetime import datetime
|
||||
import speedtest
|
||||
|
||||
# Replace these paths with the actual paths to your Pi.Alert directories
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
from plugin_helper import Plugin_Objects
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ
|
||||
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', ['[INTRSPD] In script'])
|
||||
|
||||
parser = argparse.ArgumentParser(description='Speedtest Plugin for Pi.Alert')
|
||||
values = parser.parse_args()
|
||||
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
speedtest_result = run_speedtest()
|
||||
plugin_objects.add_object(
|
||||
primaryId = 'Speedtest',
|
||||
secondaryId = timeNowTZ(),
|
||||
watched1 = speedtest_result['download_speed'],
|
||||
watched2 = speedtest_result['upload_speed'],
|
||||
watched3 = 'null',
|
||||
watched4 = 'null',
|
||||
extra = 'null',
|
||||
foreignKey = 'null'
|
||||
)
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
def run_speedtest():
|
||||
try:
|
||||
st = speedtest.Speedtest()
|
||||
st.get_best_server()
|
||||
download_speed = round(st.download() / 10**6, 2) # Convert to Mbps
|
||||
upload_speed = round(st.upload() / 10**6, 2) # Convert to Mbps
|
||||
|
||||
return {
|
||||
'download_speed': download_speed,
|
||||
'upload_speed': upload_speed,
|
||||
}
|
||||
except Exception as e:
|
||||
mylog('verbose', [f"Error running speedtest: {str(e)}"])
|
||||
return {
|
||||
'download_speed': -1,
|
||||
'upload_speed': -1,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -2,6 +2,7 @@
|
||||
"code_name": "known_template",
|
||||
"template_type": "database-entry",
|
||||
"unique_prefix": "KNWN",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "template",
|
||||
"show_ui": false,
|
||||
|
||||
9
front/plugins/maintenance/README.md
Executable file
9
front/plugins/maintenance/README.md
Executable file
@@ -0,0 +1,9 @@
|
||||
## Overview
|
||||
|
||||
A plugin responsible for general maintenance tasks. These currently include:
|
||||
|
||||
- pialert.log cleanup
|
||||
|
||||
### Usage
|
||||
|
||||
- N/A
|
||||
176
front/plugins/maintenance/config.json
Executable file
176
front/plugins/maintenance/config.json
Executable file
@@ -0,0 +1,176 @@
|
||||
{
|
||||
"code_name": "maintenance",
|
||||
"unique_prefix": "MAINT",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": false,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Maintenance"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-wrench\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin for maintenance tasks."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"type": "text.select",
|
||||
"default_value":"schedule",
|
||||
"options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuándo ejecutar"
|
||||
},
|
||||
{
|
||||
"language_code":"de_de",
|
||||
"string" : "Wann laufen"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "When the maintenance tasks should run. A daily or weekly <code>SCHEDULE</code> is a good option."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/maintenance/maintenance.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command to run. This can not be changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar. Esto no se puede cambiar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl zum Ausführen. Dies kann nicht geändert werden"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value":"0 2 * * 3",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"de_de",
|
||||
"string" : "Schedule"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#MAINT_RUN\"><code>MAINT_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#MAINT_RUN\"><code>MAINT_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>0 4 * * *</code> ejecutará el escaneo después de las 4 a.m. en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ código> que configuró arriba</a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
|
||||
},
|
||||
{
|
||||
"language_code":"de_de",
|
||||
"string" : "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#CSVBCKP_RUN\"><code>CSVBCKP_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 30,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitüberschreitung"
|
||||
}
|
||||
],
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "LOG_LENGTH",
|
||||
"type": "integer",
|
||||
"default_value": 250000,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Log length"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "How many last <code>pialert.log</code> lines to keep. If <code>LOG_LEVEL</code> is set to <code>debug</code> the app generates about 10000 lines per hour, so when debugging an issue the recommended setting should cover the bug occurence timeframe. For example for a bug with a 3 day periodical appearence the value <code>1000000</code> should be sufficient. Setting this value to <code>1000000</code> generates approximatelly a 50MB <code>pialert.log</code> file. Set to <code>0</code> to disable log purging."
|
||||
}]
|
||||
}
|
||||
],
|
||||
|
||||
"database_column_definitions":
|
||||
[
|
||||
|
||||
]
|
||||
}
|
||||
67
front/plugins/maintenance/maintenance.py
Executable file
67
front/plugins/maintenance/maintenance.py
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python
|
||||
# test script by running:
|
||||
# /home/pi/pialert/front/plugins/maintenance/maintenance.py
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import argparse
|
||||
import sys
|
||||
import hashlib
|
||||
import csv
|
||||
import sqlite3
|
||||
from io import StringIO
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
|
||||
sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"])
|
||||
|
||||
# pialert modules
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from const import logPath, pialertPath
|
||||
|
||||
|
||||
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')
|
||||
|
||||
pluginName = 'MAINT'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
MAINT_LOG_LENGTH = int(get_setting_value('MAINT_LOG_LENGTH'))
|
||||
|
||||
# Check if set
|
||||
if MAINT_LOG_LENGTH != 0:
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Cleaning file'])
|
||||
|
||||
logFile = logPath + "/pialert.log"
|
||||
|
||||
# Using a deque to efficiently keep the last N lines
|
||||
lines_to_keep = deque(maxlen=MAINT_LOG_LENGTH)
|
||||
|
||||
with open(logFile, 'r') as file:
|
||||
# Read lines from the file and store the last N lines
|
||||
for line in file:
|
||||
lines_to_keep.append(line)
|
||||
|
||||
with open(logFile, 'w') as file:
|
||||
# Write the last N lines back to the file
|
||||
file.writelines(lines_to_keep)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Cleanup finished'])
|
||||
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# BEGIN
|
||||
#===============================================================================
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -2,6 +2,7 @@
|
||||
"code_name": "Devices.new",
|
||||
"template_type": "database-entry",
|
||||
"unique_prefix": "NEWDEV",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "template",
|
||||
"show_ui": false,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "nmap_scan",
|
||||
"unique_prefix": "NMAP",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"data_filters": [
|
||||
@@ -42,13 +43,13 @@
|
||||
{
|
||||
"name" : "ips",
|
||||
"type" : "sql",
|
||||
"value" : "SELECT dev_LastIP from DEVICES",
|
||||
"value" : "SELECT dev_LastIP from DEVICES order by dev_MAC",
|
||||
"timeoutMultiplier" : true
|
||||
},
|
||||
{
|
||||
"name" : "macs",
|
||||
"type" : "sql",
|
||||
"value" : "SELECT dev_MAC from DEVICES"
|
||||
"value" : "SELECT dev_MAC from DEVICES order by dev_MAC"
|
||||
},
|
||||
{
|
||||
"name" : "timeout",
|
||||
|
||||
@@ -119,7 +119,7 @@ def performNmapScan(deviceIPs, deviceMACs, timeoutSec, args):
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occured, handle it
|
||||
mylog('none', ["[NMAP Scan] " ,e.output])
|
||||
mylog('none', ["[NMAP Scan] Error - Nmap Scan - check logs", progress])
|
||||
mylog('none', ["[NMAP Scan] ⚠ ERROR - Nmap Scan - check logs", progress])
|
||||
except subprocess.TimeoutExpired as timeErr:
|
||||
mylog('verbose', ['[NMAP Scan] Nmap TIMEOUT - the process forcefully terminated as timeout reached for ', ip, progress])
|
||||
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
{
|
||||
"code_name": "pholus_scan",
|
||||
"unique_prefix": "PHOLUS",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"mapped_to_table": "Pholus_Scan",
|
||||
"mapped_to_table": "Pholus_Scan",
|
||||
"data_filters": [
|
||||
{
|
||||
"compare_column" : "Object_PrimaryID",
|
||||
"compare_operator" : "==",
|
||||
"compare_field_id": "txtMacFilter",
|
||||
"compare_js_template": "'{value}'.toString()",
|
||||
"compare_use_quotes": true
|
||||
"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"],
|
||||
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -34,7 +38,7 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-search\"></i>"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -44,56 +48,70 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Este plugin sirve para ejecutar un escaneo Pholus (descubrimiento de nombres) en la red local"
|
||||
}
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
"params": [
|
||||
{
|
||||
"name" : "subnets",
|
||||
"type" : "setting",
|
||||
"value" : "SCAN_SUBNETS",
|
||||
"base64": true
|
||||
"name": "subnets",
|
||||
"type": "setting",
|
||||
"value": "SCAN_SUBNETS",
|
||||
"base64": true
|
||||
},
|
||||
{
|
||||
"name" : "timeout",
|
||||
"type" : "setting",
|
||||
"value" : "PHOLUS_RUN_TIMEOUT"
|
||||
}
|
||||
],
|
||||
|
||||
"name": "timeout",
|
||||
"type": "setting",
|
||||
"value": "PHOLUS_RUN_TIMEOUT"
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"type": "text.select",
|
||||
"default_value":"schedule",
|
||||
"options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
|
||||
"localized": ["name", "description"],
|
||||
"events": ["run"],
|
||||
"name" :[
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuando ejecutar"
|
||||
}],
|
||||
"function": "RUN",
|
||||
"type": "text.select",
|
||||
"default_value": "on_new_device",
|
||||
"options": [
|
||||
"disabled",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan",
|
||||
"on_new_device"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuando ejecutar"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "<a href=\"https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/pholus_scan/pholus\" target=\"_blank\" >Pholus</a> is a sniffing tool to discover additional information about the devices on the network, including the device name. If enabled this will execute the scan before every network scan cycle until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Please be aware it can spam the network with unnecessary traffic. Depends on the <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code> setting</a>. For a scheduled or one-off scan, check the <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code> setting</a>.Specify when your Name-discovery scan will run. Typical setting would be <code>on_new_device</code> or <code>schedule</code> and then you specify a cron-like schedule in the <a href=\"#PHOLUS_RUN_SCHD\"><code>PHOLUS_RUN_SCHD</code>setting</a>."
|
||||
},
|
||||
"language_code": "en_us",
|
||||
"string": "<a href=\"https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/pholus_scan/pholus\" target=\"_blank\" >Pholus</a> is a sniffing tool to discover additional information about the devices on the network, including the device name. If enabled this will execute the scan before every network scan cycle until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Please be aware it can spam the network with unnecessary traffic. Depends on the <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code> setting</a>. For a scheduled or one-off scan, check the <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code> setting</a>.Specify when your Name-discovery scan will run. Typical setting would be <code>on_new_device</code> or <code>schedule</code> and then you specify a cron-like schedule in the <a href=\"#PHOLUS_RUN_SCHD\"><code>PHOLUS_RUN_SCHD</code>setting</a>."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "<a href=\"https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/pholus_scan/pholus\" target=\"_blank\" >Pholus</a> es una herramienta de rastreo para descubrir información adicional sobre los dispositivos en la red, incluido el nombre del dispositivo. Si está habilitado, ejecutará el escaneo antes de cada ciclo de escaneo de red hasta que no haya dispositivos <code>(unknown)</code> o <code>(name not found)</code>. Tenga en cuenta que puede enviar spam a la red con tráfico innecesario. Depende de la configuración de <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code></a>. Para un análisis programado o único, verifique la configuración de <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code></a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
"language_code": "es_es",
|
||||
"string": "<a href=\"https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/pholus_scan/pholus\" target=\"_blank\" >Pholus</a> es una herramienta de rastreo para descubrir información adicional sobre los dispositivos en la red, incluido el nombre del dispositivo. Si está habilitado, ejecutará el escaneo antes de cada ciclo de escaneo de red hasta que no haya dispositivos <code>(unknown)</code> o <code>(name not found)</code>. Tenga en cuenta que puede enviar spam a la red con tráfico innecesario. Depende de la configuración de <a onclick=\"toggleAllSettings()\" href=\"#SCAN_SUBNETS\"><code>SCAN_SUBNETS</code></a>. Para un análisis programado o único, verifique la configuración de <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code></a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "readonly",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/pholus_scan/script.py userSubnets={subnets} timeoutSec={timeout}",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -102,7 +120,7 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -112,16 +130,18 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando para ejecutar. Esto no debe ser cambiado"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 300,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -130,7 +150,7 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -140,95 +160,132 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo de escaneo de red en segundos. El escaneo de Pholus siempre durará este tiempo. Cuanto más tiempo se ejecute, más nombres de dispositivos se podrán resolver. Se dividirá por el número de subredes."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value":"30 3 * * *",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Schedule"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>30 3 * * *</code> will run the scan at 3:30 am. Will be run NEXT time the time passes. <br/>"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code></a>. Asegúrese de ingresar la programación en el formato cron correcto (por ejemplo, validar en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, al ingresar <code>30 3 * * *</code> se ejecutará el escaneo a las 3:30 am. Se ejecutará la PRÓXIMA vez que pase el tiempo. <br/>"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"function": "DAYS_DATA",
|
||||
"type": "integer",
|
||||
"default_value":30,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Retención de datos"
|
||||
}],
|
||||
"description": [
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "How many days of Pholus scan entries should be kept (globally, not device specific!) Enter <code>0</code> to disable."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuántos días de entradas de escaneo de Pholus deben conservarse (globalmente, ¡no específico del dispositivo!). El archivo <a href=\"/maintenance.php#tab_Logging\">pialert_pholus.log</a> no se modifica. Introduzca <code>0</code> para desactivar."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "WATCH",
|
||||
"type": "text.multiselect",
|
||||
"default_value":["Watched_Value1", "Watched_Value2"],
|
||||
"options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Watched"
|
||||
"function": "RUN_SCHD",
|
||||
"type": "text",
|
||||
"default_value": "30 3 * * *",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Watched"
|
||||
}] ,
|
||||
"description":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Info</li><li><code>Watched_Value2</code> is Record type</li><li><code>Watched_Value3</code> is Info </li><li><code>Watched_Value4</code> is N/A </li></ul>"
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Schedule"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>30 3 * * *</code> will run the scan at 3:30 am. Will be run NEXT time the time passes. <br/>"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Enviar una notificación si los valores seleccionados cambian. Utilice <code>CTRL + Clic</code> para seleccionar/deseleccionar. <ul> <li><code>Watched_Value1</code> es Información</li><li><code>Watched_Value2</code> es Tipo de registro</li><li><code>Watched_Value3</code> es La información </li><li><code>Watched_Value4</code> es N/A </li></ul>"
|
||||
}]
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#PHOLUS_RUN\"><code>PHOLUS_RUN</code></a>. Asegúrese de ingresar la programación en el formato cron correcto (por ejemplo, validar en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, al ingresar <code>30 3 * * *</code> se ejecutará el escaneo a las 3:30 am. Se ejecutará la PRÓXIMA vez que pase el tiempo. <br/>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "DAYS_DATA",
|
||||
"type": "integer",
|
||||
"default_value": 30,
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Retención de datos"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "How many days of Pholus scan entries should be kept (globally, not device specific!) Enter <code>0</code> to disable."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuántos días de entradas de escaneo de Pholus deben conservarse (globalmente, ¡no específico del dispositivo!). El archivo <a href=\"/maintenance.php#tab_Logging\">pialert_pholus.log</a> no se modifica. Introduzca <code>0</code> para desactivar."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "WATCH",
|
||||
"type": "text.multiselect",
|
||||
"default_value": [
|
||||
"Watched_Value1",
|
||||
"Watched_Value2"
|
||||
],
|
||||
"options": [
|
||||
"Watched_Value1",
|
||||
"Watched_Value2",
|
||||
"Watched_Value3",
|
||||
"Watched_Value4"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Watched"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Watched"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is Info</li><li><code>Watched_Value2</code> is Record type</li><li><code>Watched_Value3</code> is Info </li><li><code>Watched_Value4</code> is N/A </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Enviar una notificación si los valores seleccionados cambian. Utilice <code>CTRL + Clic</code> para seleccionar/deseleccionar. <ul> <li><code>Watched_Value1</code> es Información</li><li><code>Watched_Value2</code> es Tipo de registro</li><li><code>Watched_Value3</code> es La información </li><li><code>Watched_Value4</code> es N/A </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "text.multiselect",
|
||||
"default_value": ["new"],
|
||||
"options": ["new", "watched-changed", "watched-not-changed", "missing-in-last-scan"],
|
||||
"localized": ["name", "description"],
|
||||
"default_value": [
|
||||
"new"
|
||||
],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Report on"
|
||||
},
|
||||
{
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -238,173 +295,201 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuándo debe enviarse una notificación."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"database_column_definitions":
|
||||
[
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"mapped_to_column": "MAC",
|
||||
"mapped_to_column": "MAC",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_name_mac",
|
||||
"default_value":"",
|
||||
"type": "device_name_mac",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "MAC"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "MAC"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"mapped_to_column": "IP_v4_or_v6",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "IP"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "IP"
|
||||
}]
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"mapped_to_column": "Info",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Info"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Info"
|
||||
}]
|
||||
} ,
|
||||
"column": "Object_SecondaryID",
|
||||
"mapped_to_column": "IP_v4_or_v6",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"mapped_to_column": "Record_Type",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Type"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Tipo"
|
||||
}]
|
||||
} ,
|
||||
"column": "Watched_Value1",
|
||||
"mapped_to_column": "Info",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Info"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Info"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"mapped_to_column": "Value",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Info"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Info"
|
||||
}]
|
||||
"column": "Watched_Value2",
|
||||
"mapped_to_column": "Record_Type",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Type"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tipo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value3",
|
||||
"mapped_to_column": "Value",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Info"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Info"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"mapped_to_column": "Time",
|
||||
"mapped_to_column": "Time",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Created"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Creado"
|
||||
}]
|
||||
},
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Created"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[
|
||||
{
|
||||
"language_code":"en_us",
|
||||
"string" : "Changed"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cambiado"
|
||||
}
|
||||
]
|
||||
},
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value":"",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Status"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Estado"
|
||||
}]
|
||||
}
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -94,8 +94,7 @@ def main():
|
||||
|
||||
|
||||
def execute_pholus_scan(userSubnets, timeoutSec):
|
||||
# output of possible multiple interfaces
|
||||
arpscan_output = ""
|
||||
# output of possible multiple interfaces
|
||||
result_list = []
|
||||
|
||||
timeoutPerSubnet = float(timeoutSec) / len(userSubnets)
|
||||
@@ -151,7 +150,7 @@ def execute_pholus_on_interface(interface, timeoutSec, mask):
|
||||
except subprocess.CalledProcessError as e:
|
||||
# An error occured, handle it
|
||||
mylog('none', ['[PHOLUS]', e.output])
|
||||
mylog('none', ["[PHOLUS] Error - Pholus Scan - check logs"])
|
||||
mylog('none', ["[PHOLUS] ⚠ ERROR - Pholus Scan - check logs"])
|
||||
except subprocess.TimeoutExpired as timeErr:
|
||||
mylog('none', ['[PHOLUS] Pholus TIMEOUT - the process forcefully terminated as timeout reached'])
|
||||
|
||||
|
||||
@@ -5,4 +5,7 @@ A plugin allowing for importing devices from the PiHole database. This is an imp
|
||||
|
||||
### Usage
|
||||
|
||||
- You need to specify the `PIHOLE_RUN_SCHD` setting and map the PiHole DB file to the path specified in the `PIHOLE_DB_PATH` setting.
|
||||
- You need to specify the following settings:
|
||||
- `PIHOLE_RUN` is used to enable the import by setting it e.g. to `schedule` or `once` (pre-set to `disabled`)
|
||||
- `PIHOLE_RUN_SCHD` is to configure how often the plugin is executed if `PIHOLE_RUN` is set to `schedule` (pre-set to every 30 min)
|
||||
- `PIHOLE_DB_PATH` setting must match the location of your PiHole database (pre-set to `/etc/pihole/pihole-FTL.db`)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "pihole_scan",
|
||||
"unique_prefix": "PIHOLE",
|
||||
"plugin_type": "device_scanner",
|
||||
"enabled": true,
|
||||
"data_source": "sqlite-db-query",
|
||||
"mapped_to_table": "CurrentScan",
|
||||
@@ -82,7 +83,7 @@
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "text",
|
||||
"default_value":"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 <> {s-quote}00:00:00:00:00:00{s-quote};",
|
||||
"default_value":"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 <> {s-quote}00:00:00:00:00:00{s-quote} AND na.ip <> null;",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
@@ -104,7 +105,7 @@
|
||||
},
|
||||
{
|
||||
"function": "DB_PATH",
|
||||
"type": "readonly",
|
||||
"type": "text",
|
||||
"default_value":"/etc/pihole/pihole-FTL.db",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from time import strftime
|
||||
import pytz
|
||||
import sys
|
||||
import re
|
||||
import base64
|
||||
from datetime import datetime
|
||||
|
||||
@@ -38,7 +39,11 @@ def handleEmpty(input):
|
||||
if input == '' or None:
|
||||
return 'null'
|
||||
else:
|
||||
return input
|
||||
# Validate and sanitize message content
|
||||
# Remove potentially problematic characters if string
|
||||
if isinstance(input, str):
|
||||
input = re.sub(r'[^\x00-\x7F]+', ' ', input)
|
||||
return input
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
def decodeBase64(inputParamBase64):
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"code_name": "set_password",
|
||||
"template_type": "database-entry",
|
||||
"unique_prefix": "SETPWD",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": false,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "snmp_discovery",
|
||||
"unique_prefix": "SNMPDSC",
|
||||
"plugin_type": "device_scanner",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"data_filters": [
|
||||
|
||||
@@ -75,15 +75,14 @@ def main():
|
||||
ipAddress = '.'.join(ipStr)
|
||||
|
||||
mylog('verbose', [f'[SNMPDSC] IP: {ipAddress} MAC: {macAddress}'])
|
||||
|
||||
|
||||
plugin_objects.add_object(
|
||||
primaryId=macAddress,
|
||||
secondaryId=ipAddress.strip(), # Remove leading/trailing spaces from IP
|
||||
watched1='(unknown)',
|
||||
watched2=snmpwalkArgs[6], # router IP
|
||||
extra=line,
|
||||
foreignKey=macAddress # Use the primary ID as the foreign key
|
||||
primaryId = handleEmpty(macAddress),
|
||||
secondaryId = handleEmpty(ipAddress.strip()), # Remove leading/trailing spaces from IP
|
||||
watched1 = '(unknown)',
|
||||
watched2 = handleEmpty(snmpwalkArgs[6]), # router IP
|
||||
extra = handleEmpty(line),
|
||||
foreignKey = handleEmpty(macAddress) # Use the primary ID as the foreign key
|
||||
)
|
||||
|
||||
mylog('verbose', ['[SNMPDSC] Entries found: ', len(plugin_objects)])
|
||||
|
||||
27
front/plugins/undiscoverables/README_DE.md
Executable file
27
front/plugins/undiscoverables/README_DE.md
Executable file
@@ -0,0 +1,27 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zum Importieren von nicht erkennbaren Geräten aus einer Datei. Das Plugin findet Verwendung, wenn "dumme" Netzwerkkomponenten (z.B. Unmanaged Hubs/Switches) zur Netzwerkansicht hinzugefügt werden sollen. Möglicherweise gibt es weitere Anwendungsfälle, bitte informiert uns darüber.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Einstellungen aufrufen und Nicht erkennbare Geräte in der Liste der Plugins finden
|
||||
- Plugin aktivieren, indem der `RUN`-Parameter von `disabled` zu `once` oder `always_after_scan` geändert wird
|
||||
- Gerätenamen der Liste hinzufügen (Beispieleintrag zuerst entfernen)
|
||||
- SPEICHERN
|
||||
- Auf Abschluss des nächsten Scans warten
|
||||
|
||||
#### Beispiele
|
||||
|
||||
Einstellungen:
|
||||

|
||||
|
||||
Resultat:
|
||||

|
||||
|
||||
Erlaubt nicht erkennbare Geräte wie Hubs, Switches oder APs in der Netzwerkansicht:
|
||||

|
||||
|
||||
### Bekannte Einschränkungen
|
||||
|
||||
- Nicht erkennbare Geräte erscheinen immer als Offline. Pi.Alert kann diese Geräte nicht erkennen (wie erwartet).
|
||||
- Alle IPs werden auf 0.0.0.0 gesetzt, daher kann es sein, dass das "Zufällige MAC"-Icon erscheint
|
||||
@@ -1,12 +1,16 @@
|
||||
{
|
||||
"code_name": "undiscoverables",
|
||||
"unique_prefix": "UNDIS",
|
||||
"plugin_type": "device_scanner",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -15,7 +19,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dispositivos no detectables"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nicht erkennbare Geräte"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
@@ -25,7 +33,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-binoculars\"></i>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-binoculars\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -35,46 +47,74 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Este complemento es para importar dispositivos no detectables desde un archivo."
|
||||
}
|
||||
],
|
||||
"params" : [
|
||||
},
|
||||
{
|
||||
"name" : "devices",
|
||||
"type" : "setting",
|
||||
"value" : "UNDIS_devices_to_import"
|
||||
}],
|
||||
|
||||
"language_code": "de_de",
|
||||
"string": "Ein Plugin zum Importieren von nicht erkennbaren Geräten aus einer Datei."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "devices",
|
||||
"type": "setting",
|
||||
"value": "UNDIS_devices_to_import"
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"type": "text.select",
|
||||
"default_value":"disabled",
|
||||
"options": ["disabled", "once", "always_after_scan"],
|
||||
"localized": ["name", "description"],
|
||||
"name" :[{
|
||||
"language_code":"en_us",
|
||||
"string" : "When to run"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuándo ejecuta"
|
||||
}],
|
||||
"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.<br> Changes will only show in the devices <b> after the next scan!</b>"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cuando está habilitado, ONCE es la opción preferida. Se ejecuta al inicio y después de cada guardado de la configuración aquí.<br> ¡Los cambios solo se mostrarán en los dispositivos <b> después del próximo escaneo!</b>"
|
||||
}]
|
||||
},
|
||||
"function": "RUN",
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"once",
|
||||
"always_after_scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuándo ejecuta"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"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.<br> Changes will only show in the devices <b> after the next scan!</b>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuando está habilitado, ONCE es la opción preferida. Se ejecuta al inicio y después de cada guardado de la configuración aquí.<br> ¡Los cambios solo se mostrarán en los dispositivos <b> después del próximo escaneo!</b>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wenn dieses Plugin aktiviert ist, ist <code>once</code> die bevorzugte Methode. Das Plugin wird dann bei jedem Start und nach jedem Speichern der Einstellungen ausgeführt.</br>Änderungen scheinen in den Geräten erst <b>nach dem nächsten Scan</b> auf!"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": "text",
|
||||
"default_value": "python3 /home/pi/pialert/front/plugins/undiscoverables/script.py devices={devices}",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -83,7 +123,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -93,16 +137,22 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar. Esto no se puede cambiar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl zum Ausführen. Dies kann nicht geändert werden"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": "integer",
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -111,7 +161,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitlimit"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -121,7 +175,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -129,7 +187,10 @@
|
||||
"type": "readonly",
|
||||
"default_value": [],
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -138,7 +199,12 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Visto"
|
||||
}],
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -147,15 +213,27 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Los dispositivos no detectables no pueden cambiar su estado, ningún reloj está habilitado."
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status von nicht erkennbaren Geräten können sich nicht ändern, keine Überwachung aktiviert."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "REPORT_ON",
|
||||
"type": "readonly",
|
||||
"default_value": [],
|
||||
"options": ["new", "watched-changed", "watched-not-changed", "missing-in-last-scan"],
|
||||
"localized": ["name", "description"],
|
||||
"options": [
|
||||
"new",
|
||||
"watched-changed",
|
||||
"watched-not-changed",
|
||||
"missing-in-last-scan"
|
||||
],
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
@@ -164,7 +242,11 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
@@ -174,162 +256,237 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "No se enviarán notificaciones."
|
||||
}
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Keine Benachrichtigungen werden versendet."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "devices_to_import",
|
||||
"type": "list",
|
||||
"default_value":["dummy_router"],
|
||||
"default_value": [
|
||||
"dummy_router"
|
||||
],
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name" : [{
|
||||
"language_code":"en_us",
|
||||
"string" : "UnDiscoverable Devices"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Dispositivo no detectable"
|
||||
}],
|
||||
"description": [{
|
||||
"language_code":"en_us",
|
||||
"string" : "Devices to be added to the devices list."
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Dispositivos que se añadirán a la lista de dispositivos."
|
||||
}]
|
||||
}
|
||||
"localized": [
|
||||
"name",
|
||||
"description"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "UnDiscoverable Devices"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dispositivo no detectable"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nicht erkennbare Geräte"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Devices to be added to the devices list."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dispositivos que se añadirán a la lista de dispositivos."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geräte, welche der Geräteliste hinzugefügt werden."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
"database_column_definitions":
|
||||
[
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"mapped_to_column": "cur_Name",
|
||||
"mapped_to_column": "cur_Name",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Device Name"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Nombre del dispositivo"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"mapped_to_column": "cur_MAC",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "MAC address"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Dirección MAC"
|
||||
}]
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Device Name"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Nombre del dispositivo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Gerätename"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "IP"
|
||||
}]
|
||||
} ,
|
||||
"column": "Object_PrimaryID",
|
||||
"mapped_to_column": "cur_MAC",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC address"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dirección MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC-Adresse"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Created"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Creado"
|
||||
}]
|
||||
},
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Created"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Erstellt"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"mapped_to_column": "cur_DateTime",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Changed"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Cambiado"
|
||||
}]
|
||||
"column": "DateTimeChanged",
|
||||
"mapped_to_column": "cur_DateTime",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Dummy",
|
||||
"mapped_to_column": "cur_ScanMethod",
|
||||
"mapped_to_column": "cur_ScanMethod",
|
||||
"mapped_to_column_data": {
|
||||
"value": "UNDIS"
|
||||
},
|
||||
"value": "UNDIS"
|
||||
},
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value":"",
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "Scan method"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "Método de escaneo"
|
||||
}]
|
||||
} ,
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Scan method"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Método de escaneo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Scanmethode"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "ForeignKey",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": false,
|
||||
"type": "device_mac",
|
||||
"default_value":"",
|
||||
"type": "device_mac",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name":[{
|
||||
"language_code":"en_us",
|
||||
"string" : "MAC"
|
||||
},
|
||||
{
|
||||
"language_code":"es_es",
|
||||
"string" : "MAC"
|
||||
}]
|
||||
}
|
||||
"localized": [
|
||||
"name"
|
||||
],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,78 @@
|
||||
{
|
||||
"code_name": "unifi_import",
|
||||
"show_ui": true,
|
||||
"unique_prefix": "UNFIMP",
|
||||
"plugin_type": "device_scanner",
|
||||
"data_source": "script",
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "UniFi import"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Importación UniFi"
|
||||
}
|
||||
],
|
||||
"enabled": true,
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-upload\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-upload\"></i>"
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "username",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_username"
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_password"
|
||||
},
|
||||
{
|
||||
"name": "host",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_host"
|
||||
},
|
||||
{
|
||||
"name": "sites",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_sites"
|
||||
},
|
||||
{
|
||||
"name": "port",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_port"
|
||||
},
|
||||
{
|
||||
"name": "verifyssl",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_verifyssl"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_version"
|
||||
},
|
||||
{
|
||||
"name": "fullimport",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_fullimport"
|
||||
}
|
||||
],
|
||||
"data_filters": [
|
||||
{
|
||||
"compare_column": "Object_PrimaryID",
|
||||
@@ -8,8 +81,7 @@
|
||||
"compare_operator": "==",
|
||||
"compare_use_quotes": true
|
||||
}
|
||||
],
|
||||
"data_source": "script",
|
||||
],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Index",
|
||||
@@ -400,76 +472,7 @@
|
||||
"language_code": "de_de",
|
||||
"string": "Dieses Plugin imporiert die Geräte von einem UNIFI Controller."
|
||||
}
|
||||
],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "UniFi import"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Importación UniFi"
|
||||
}
|
||||
],
|
||||
"enabled": true,
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-upload\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "<i class=\"fa-solid fa-upload\"></i>"
|
||||
}
|
||||
],
|
||||
"localized": [
|
||||
"display_name",
|
||||
"description",
|
||||
"icon"
|
||||
],
|
||||
"mapped_to_table": "CurrentScan",
|
||||
"params": [
|
||||
{
|
||||
"name": "username",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_username"
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_password"
|
||||
},
|
||||
{
|
||||
"name": "host",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_host"
|
||||
},
|
||||
{
|
||||
"name": "sites",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_sites"
|
||||
},
|
||||
{
|
||||
"name": "port",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_port"
|
||||
},
|
||||
{
|
||||
"name": "verifyssl",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_verifyssl"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_version"
|
||||
},
|
||||
{
|
||||
"name": "fullimport",
|
||||
"type": "setting",
|
||||
"value": "UNFIMP_fullimport"
|
||||
}
|
||||
],
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"default_value": "disabled",
|
||||
@@ -950,7 +953,5 @@
|
||||
],
|
||||
"type": "text.select"
|
||||
}
|
||||
],
|
||||
"show_ui": true,
|
||||
"unique_prefix": "UNFIMP"
|
||||
]
|
||||
}
|
||||
|
||||
7
front/plugins/vendor_update/README_DE.md
Executable file
7
front/plugins/vendor_update/README_DE.md
Executable file
@@ -0,0 +1,7 @@
|
||||
## Übersicht
|
||||
|
||||
Ein Plugin zum Herunterladen einer MAC- und Hersteller-Datenbank für die Erkennung vom Hersteller eines Gerätes. Das Resultat des Plugins ist eine Liste von Herstellern, verknüpft zu Geräten, deren Hersteller bisher unbekannt war.
|
||||
|
||||
### Verwendung
|
||||
|
||||
- Einstellungen-Seite für Details ansehen.
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "vendor_update",
|
||||
"unique_prefix": "VNDRPDT",
|
||||
"plugin_type": "system",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
@@ -13,25 +14,39 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Vendor update"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Hersteller Update"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-landmark-flag\"></i>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "<i class=\"fa-solid fa-landmark-flag\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to schedule vendor database updates for mac based vendor resolution."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Ein Plugin zum Updaten der Herstellerdatenbank für MAC-basierte Herstellerauflösung."
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"events": [
|
||||
"run"
|
||||
],
|
||||
"type": "text.select",
|
||||
"default_value": "schedule",
|
||||
"options": [
|
||||
@@ -55,13 +70,17 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann laufen"
|
||||
"string": "Wann ausführen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When the plugin should run. An overnight weekly <code>SCHEDULE</code> is recommended."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann das Plugin ausgeführt werden soll. Eine wöchentliche <code>SCHEDULE</code> in der Nacht wird empfohlen."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -123,7 +142,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Schedule"
|
||||
"string": "Zeitplan"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -137,7 +156,7 @@
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#VNDRPDT_RUN\"><code>VNDRPDT_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
"string": "Nur aktiv, wenn <code>schedule</code> in der <a href=\"#VNDRPDT_RUN\"><code>VNDRPDT_RUN</code> Einstellung</a> ausgewählt wurde. Sichergehen, dass das Intervall in einem korrekten cron-ähnlichen Format angegeben wurde (z.B. auf <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a> testen). <code>0 4 * * *</code> würde den Scan täglich um 4 Uhr in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\">oben ausgewählten <code>TIMEZONE</code></a> starten. Wird erst beim NÄCHSTEN Intervall ausgeführt. <br/>Es wird empfohlen, das Intervall aller Plugins, welche nach neuen Geräten suchen, auf den gleichen Wert zu setzen."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -203,12 +222,20 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Visto"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Überwacht"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is vendor name</li><li><code>Watched_Value2</code> is device name</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Sende eine Benachrichtigung, wenn ein ausgwählter Wert sich ändert. <code>STRG + klicken</code> zum aus-/abwählen. <ul> <li><code>Watched_Value1</code> ist der Herstellername</li><li><code>Watched_Value2</code> ist der Gerätename</li><li><code>Watched_Value3</code> ist nicht in Verwendung </li><li><code>Watched_Value4</code> ist nicht in Verwendung </li></ul>"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -237,6 +264,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Informar sobre"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige wenn"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
@@ -247,6 +278,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Envíe una notificación solo en estos estados. <code>new</code> significa que se descubrió un nuevo objeto único (combinación única de PrimaryId y SecondaryId). <code>watched-changed</code> significa que seleccionó <code>Watched_ValueN Las columnas </code> cambiaron."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Benachrichtige nur bei diesen Status. <code>new</code> bedeutet ein neues eindeutiges (einzigartige Kombination aus PrimaryId und SecondaryId) Objekt wurde erkennt. <code>watched-changed</code> bedeutet eine ausgewählte <code>Watched_ValueN</code>-Spalte hat sich geändert."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -270,6 +305,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -291,6 +330,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -313,6 +356,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Dirección MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "MAC-Adresse"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -335,6 +382,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -356,6 +407,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Creado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Erstellt"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -378,6 +433,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cambiado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Geändert"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -403,6 +462,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Método de escaneo"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Scanmethode"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -421,6 +484,10 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Vendor"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Hersteller"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -443,6 +510,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Nombre de host"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Hostname"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -460,6 +531,10 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -477,6 +552,10 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -498,6 +577,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comentarios"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Kommentare"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -515,6 +598,10 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "N/A"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "N/A"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -553,6 +640,10 @@
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Estado"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ from datetime import datetime
|
||||
sys.path.append("/home/pi/pialert/front/plugins")
|
||||
sys.path.append('/home/pi/pialert/pialert')
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64, handleEmpty
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ
|
||||
from const import logPath, pialertPath
|
||||
@@ -106,14 +106,14 @@ def update_vendors (dbPath, plugin_objects):
|
||||
ignored += 1
|
||||
else :
|
||||
plugin_objects.add_object(
|
||||
primaryId = device[0], # MAC (Device Name)
|
||||
secondaryId = device[1], # IP Address (always 0.0.0.0)
|
||||
watched1 = vendor,
|
||||
watched2 = device[2], # Device name
|
||||
primaryId = handleEmpty(device[0]), # MAC (Device Name)
|
||||
secondaryId = handleEmpty(device[1]), # IP Address (always 0.0.0.0)
|
||||
watched1 = handleEmpty(vendor),
|
||||
watched2 = handleEmpty(device[2]), # Device name
|
||||
watched3 = "",
|
||||
watched4 = "",
|
||||
extra = "",
|
||||
foreignKey = device[0]
|
||||
foreignKey = handleEmpty(device[0])
|
||||
)
|
||||
|
||||
# Print log
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"code_name": "website_monitor",
|
||||
"unique_prefix": "WEBMON",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
|
||||
@@ -89,6 +89,11 @@ function processColumnValue(dbColumnDef, value, index, type) {
|
||||
case 'label':
|
||||
value = `<span>${value}<span>`;
|
||||
break;
|
||||
case 'textarea_readonly':
|
||||
value = `<textarea cols="70" rows="3" wrap="off" readonly style="white-space: pre-wrap;">
|
||||
${value.replace(/^b'(.*)'$/gm, '$1').replace(/\\n/g, '\n').replace(/\\r/g, '\r')}
|
||||
</textarea>`;
|
||||
break;
|
||||
case 'textbox_save':
|
||||
|
||||
value = value == 'null' ? '' : value; // hide 'null' values
|
||||
@@ -131,7 +136,7 @@ function processColumnValue(dbColumnDef, value, index, type) {
|
||||
valueTmp = ''
|
||||
|
||||
$.each(dbColumnDef.options, function(index, obj) {
|
||||
if(Number(value) < obj.maximum && valueTmp == '')
|
||||
if(Number(value) < Number(obj.maximum) && valueTmp == '')
|
||||
{
|
||||
valueTmp = `<div style="background-color:${obj.hexColor}">${value}</div>`
|
||||
// return;
|
||||
@@ -164,6 +169,15 @@ function processColumnValue(dbColumnDef, value, index, type) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'eval':
|
||||
|
||||
for (const option of dbColumnDef.options) {
|
||||
if (option.type === type) {
|
||||
console.log(option.param)
|
||||
value = eval(option.param);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
value = value + `<div style='text-align:center' title="${getString("Plugins_no_control")}"><i class='fa-solid fa-circle-question'></i></div>` ;
|
||||
|
||||
166
front/report.php
166
front/report.php
@@ -30,20 +30,160 @@
|
||||
<!-- Main content ---------------------------------------------------------- -->
|
||||
<section class="content">
|
||||
|
||||
<?php
|
||||
// Check if the page exists
|
||||
if (file_exists("api/notification_text.html")) {
|
||||
// Load the page
|
||||
include("api/notification_text.html");
|
||||
} else {
|
||||
// Display an error message
|
||||
echo "<h2>Error</h2>";
|
||||
echo lang('REPORT_ERROR');
|
||||
}
|
||||
?>
|
||||
<div class="col-sm-2">
|
||||
<!-- Display data and navigation buttons -->
|
||||
<div id="notificationContainer">
|
||||
<div id="navigationButtons">
|
||||
<button class="btn btn-default text-gray50" id="prevButton">
|
||||
<i class="fa fa-chevron-left"></i>
|
||||
</button>
|
||||
<span id="notificationOutOff"></span>
|
||||
<button class="btn btn-default text-gray50" id="nextButton">
|
||||
<i class="fa fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<!-- Select format -->
|
||||
<div class="col-sm-2 ">
|
||||
<label for="formatSelect">
|
||||
<?= lang('report_select_format') ;?>
|
||||
</label>
|
||||
<select id="formatSelect" class="pointer">
|
||||
<option value="HTML">HTML</option>
|
||||
<option value="JSON">JSON</option>
|
||||
<option value="Text">Text</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-4">
|
||||
<label><?= lang('report_time') ;?></label>
|
||||
<span id="timestamp"></span>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<label><?= lang('report_guid') ;?></label>
|
||||
<span id="guid"></span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12" id="notificationData">
|
||||
<!-- Data will be displayed here -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- JavaScript to fetch and display data based on selected format -->
|
||||
<script>
|
||||
// JavaScript to fetch and display data based on selected format
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const notificationData = document.getElementById('notificationData');
|
||||
const timestamp = document.getElementById('timestamp');
|
||||
const notiGuid = document.getElementById('guid');
|
||||
const prevButton = document.getElementById('prevButton');
|
||||
const nextButton = document.getElementById('nextButton');
|
||||
const formatSelect = document.getElementById('formatSelect');
|
||||
|
||||
let currentIndex = -1; // Current report index
|
||||
|
||||
// Function to update the displayed data and timestamp based on the selected format and index
|
||||
function updateData(format, index) {
|
||||
// Fetch data from the API endpoint
|
||||
fetch('/api/table_notifications.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (index < 0) {
|
||||
index = data.data.length - 1;
|
||||
} else if (index >= data.data.length) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
const notification = data.data[index];
|
||||
const formatData = notification[format];
|
||||
|
||||
// Display the selected format data and update timestamp
|
||||
switch (format) {
|
||||
case 'HTML':
|
||||
notificationData.innerHTML = formatData;
|
||||
break;
|
||||
case 'JSON':
|
||||
notificationData.innerHTML = `<pre class="logs" cols="70" rows="10" wrap="off" readonly="">
|
||||
${jsonSyntaxHighlight(JSON.stringify(JSON.parse(formatData), undefined, 4))}
|
||||
</pre>`;
|
||||
break;
|
||||
case 'Text':
|
||||
notificationData.innerHTML = `<pre class="logs" cols="70" rows="10" wrap="off" readonly">${formatData}</pre>`;
|
||||
break;
|
||||
}
|
||||
|
||||
// console.log(notification)
|
||||
|
||||
timestamp.textContent = notification.DateTimeCreated;
|
||||
notiGuid.textContent = notification.GUID;
|
||||
currentIndex = index;
|
||||
|
||||
$("#notificationOutOff").html(`${currentIndex + 1}/${data.data.length}`);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to find the index of a notification by GUID
|
||||
function findIndexByGUID(data, guid) {
|
||||
return data.findIndex(notification => notification.GUID == guid);
|
||||
}
|
||||
|
||||
// Listen for format selection changes
|
||||
formatSelect.addEventListener('change', () => {
|
||||
updateData(formatSelect.value, currentIndex);
|
||||
});
|
||||
|
||||
// Listen for previous button click
|
||||
prevButton.addEventListener('click', () => {
|
||||
updateData(formatSelect.value, currentIndex - 1);
|
||||
});
|
||||
|
||||
// Listen for next button click
|
||||
nextButton.addEventListener('click', () => {
|
||||
updateData(formatSelect.value, currentIndex + 1);
|
||||
});
|
||||
|
||||
// Check if there is a GUID query parameter
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has('guid')) {
|
||||
const guid = urlParams.get('guid');
|
||||
fetch('/api/table_notifications.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const index = findIndexByGUID(data.data, guid);
|
||||
|
||||
console.log(index)
|
||||
|
||||
if (index == -1) {
|
||||
showModalOk('WARNING', `${getString("report_guid_missing")} <br/> <br/> <code>${guid}</code>`)
|
||||
}
|
||||
|
||||
// Load the notification with the specified GUID
|
||||
updateData(formatSelect.value, index);
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
} else {
|
||||
|
||||
// Initial data load
|
||||
updateData('HTML', -1); // Default format to HTML and load the latest report
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<!-- /.content -->
|
||||
<?php
|
||||
|
||||
@@ -54,6 +54,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
<!-- Page ------------------------------------------------------------------ -->
|
||||
|
||||
<script src="js/pialert_common.js"></script>
|
||||
<script src="js/settings_utils.js"></script>
|
||||
|
||||
|
||||
<div id="settingsPage" class="content-wrapper">
|
||||
@@ -70,10 +71,68 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
</span>
|
||||
</a>
|
||||
</h1>
|
||||
<div class="settingsImported"><?= lang("settings_imported");?> <span id="lastImportedTime"></span></div>
|
||||
|
||||
<div class="col-sm-2 " title="<?= lang("settings_imported");?> ">
|
||||
<div class="settingsImported">
|
||||
<?= lang("settings_imported_label");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<span id="lastImportedTime"></span>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
<div class="content settingswrap" id='accordion_gen'>
|
||||
<!-- PLACEHOLDER -->
|
||||
<section class="content-header">
|
||||
|
||||
<div id="settingsOverview" class ="bg-white color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<!-- Settings imported time -->
|
||||
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_enabled_icon");?>"></i> <?= lang("settings_enabled");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id=""></div>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<div class="content settingswrap " id="accordion_gen">
|
||||
|
||||
<div class ="bg-grey-dark color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_core_icon");?>"></i> <?= lang("settings_core_label");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id="core_content"></div>
|
||||
</div>
|
||||
|
||||
<div class ="bg-grey-dark color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_system_icon");?>"></i> <?= lang("settings_system_label");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id="system_content"></div>
|
||||
</div>
|
||||
|
||||
<div class ="bg-grey-dark color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_device_scanners_icon");?>"></i> <?= lang("settings_device_scanners_label");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id="device_scanner_content"></div>
|
||||
</div>
|
||||
|
||||
<div class ="bg-grey-dark color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_other_scanners_icon");?>"></i> <?= lang("settings_other_scanners_label");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id="other_content"></div>
|
||||
</div>
|
||||
|
||||
<div class ="bg-grey-dark color-palette box panel panel-default col-sm-12 box-default box-info" >
|
||||
<div class ="settings-group col-sm-12">
|
||||
<i class="<?= lang("settings_publishers_icon");?>"></i> <?= lang("settings_publishers_label");?>
|
||||
</div>
|
||||
<div class =" col-sm-12" id="publisher_content"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- /.content -->
|
||||
@@ -95,78 +154,152 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get plugin and settings data from API endpoints
|
||||
function getData(){
|
||||
|
||||
$.get('api/table_settings.json?nocache=' + Date.now(), function(res) {
|
||||
|
||||
settingsData = res["data"];
|
||||
|
||||
initSettingsPage(settingsData);
|
||||
$.get('api/plugins.json?nocache=' + Date.now(), function(res) {
|
||||
|
||||
pluginsData = res["data"];
|
||||
|
||||
initSettingsPage(settingsData, pluginsData);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function initSettingsPage(settingsData){
|
||||
// -------------------------------------------------------------------
|
||||
// main initialization function
|
||||
function initSettingsPage(settingsData, pluginsData){
|
||||
|
||||
const settingGroups = [];
|
||||
const settingKeyOfLists = [];
|
||||
// core groups are the ones not generated by plugins
|
||||
const settingCoreGroups = ['General', 'Email', 'Webhooks', 'Apprise', 'NTFY', 'PUSHSAFER', 'MQTT', 'DynDNS', 'API'];
|
||||
|
||||
const enabledDeviceScanners = getPluginsByType(pluginsData, "device_scanner", true);
|
||||
const enabledOthers = getPluginsByType(pluginsData, "other", true);
|
||||
const enabledPublishers = getPluginsByType(pluginsData, "publisher", true);
|
||||
|
||||
|
||||
// Loop through the settingsArray and collect unique settingGroups
|
||||
|
||||
// Loop through the settingsArray and:
|
||||
// - collect unique settingGroups
|
||||
// - collect enabled plugins
|
||||
|
||||
settingsData.forEach((set) => {
|
||||
// settingGroups
|
||||
if (!settingGroups.includes(set.Group)) {
|
||||
settingGroups.push(set.Group);
|
||||
}
|
||||
settingGroups.push(set.Group); // = Unique plugin prefix
|
||||
}
|
||||
});
|
||||
|
||||
// Init the overview section
|
||||
overviewSections = [
|
||||
'device_scanners',
|
||||
'other_scanners',
|
||||
'publishers'
|
||||
]
|
||||
overviewSectionsHtml = [
|
||||
pluginCards(enabledDeviceScanners,['RUN', 'RUN_SCHD']),
|
||||
pluginCards(enabledOthers, ['RUN', 'RUN_SCHD']),
|
||||
pluginCards(enabledPublishers, []),
|
||||
|
||||
]
|
||||
|
||||
index = 0
|
||||
overviewSections_html = ''
|
||||
|
||||
overviewSections.forEach((section) => {
|
||||
|
||||
overviewSections_html += `<div class="overview-section col-sm-12" id="${section}">
|
||||
<div class="col-sm-12 " title="${getString("settings_"+section)}">
|
||||
<div class="overview-group col-sm-12">
|
||||
|
||||
<i title="${section}" class="${getString("settings_"+section+"_icon")}"></i>
|
||||
|
||||
${getString("settings_"+section+"_label")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
${overviewSectionsHtml[index]}
|
||||
</div>
|
||||
</div>`
|
||||
index++;
|
||||
});
|
||||
|
||||
$('#settingsOverview').append(overviewSections_html);
|
||||
|
||||
console.log(settingGroups);
|
||||
|
||||
let headersHtml = '';
|
||||
// Display warning
|
||||
if(schedulesAreSynchronized(enabledDeviceScanners, pluginsData) == false)
|
||||
{
|
||||
$("#device_scanners").append(
|
||||
`
|
||||
<small class="label pull-right bg-red pointer" onClick="showModalOk('WARNING', '${getString("Settings_device_Scanners_desync_popup")}')">
|
||||
${getString('Settings_device_Scanners_desync')}
|
||||
</small>
|
||||
`)
|
||||
}
|
||||
|
||||
// Start constructing the main settings HTML
|
||||
let pluginHtml = `
|
||||
<div class="row table_row">
|
||||
<div class="table_cell bold">
|
||||
<i class="fa-regular fa-book fa-sm"></i>
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins" target="_blank">
|
||||
<?= lang('Gen_ReadDocs');?>
|
||||
${getString('Gen_ReadDocs')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
let isIn = ' in '; // to open the active panel in AdminLTE
|
||||
|
||||
for (const group of settingGroups) {
|
||||
let isPlugin = false;
|
||||
let settingGroupTypeHtml = '';
|
||||
for (const group of settingGroups) {
|
||||
|
||||
if (settingCoreGroups.includes(group)) {
|
||||
settingGroupTypeHtml = '';
|
||||
} else {
|
||||
settingGroupTypeHtml = ' (<i class="fa-regular fa-plug fa-sm"></i>) ';
|
||||
isPlugin = true;
|
||||
}
|
||||
// enabled / disabled icons
|
||||
enabledHtml = ''
|
||||
|
||||
headersHtml += `<div class="box panel panel-default">
|
||||
if(getSetting(group+"_RUN") != "")
|
||||
{
|
||||
let isEnabled = ["once", "schedule", "always_after_scan", "on_new_device", "on_notification", "before_config_save" ].includes(getSetting(group+"_RUN"));
|
||||
|
||||
isEnabled ? onOff = 'on' : onOff = 'off';
|
||||
|
||||
enabledHtml = `
|
||||
<div class="enabled-disabled-icon">
|
||||
<i class="fa-solid fa-toggle-${onOff}"></i>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
headerHtml = `<div class="box box-solid box-primary panel panel-default">
|
||||
<a data-toggle="collapse" data-parent="#accordion_gen" href="#${group}">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">${getString(group+"_icon")} ${getString(group+"_display_name")} ${settingGroupTypeHtml}</h4>
|
||||
<h4 class="panel-title">
|
||||
<div class="col-sm-1 col-xs-1">${getString(group+"_icon")} </div>
|
||||
<div class="col-sm-10 col-xs-8">${getString(group+"_display_name")} </div>
|
||||
<div class="col-sm-1 col-xs-1">${enabledHtml} </div>
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
<div id="${group}" data-myid="collapsible" class="panel-collapse collapse ${isIn}">
|
||||
<div class="panel-body">
|
||||
${isPlugin ? pluginHtml: ""}
|
||||
${group != "general" ? pluginHtml: ""}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
isIn = ' '; // open the first panel only by default on page load
|
||||
}
|
||||
|
||||
// generate headers/sections
|
||||
$('#accordion_gen').html(headersHtml);
|
||||
|
||||
// generate headers/sections
|
||||
$('#'+getPluginType(pluginsData, group) + "_content").append(headerHtml);
|
||||
}
|
||||
|
||||
|
||||
// generate panel content
|
||||
for (const group of settingGroups) {
|
||||
@@ -353,13 +486,13 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
const eventsList = createArray(set['Events']);
|
||||
|
||||
if (eventsList.length > 0) {
|
||||
console.log(eventsList)
|
||||
// console.log(eventsList)
|
||||
eventsList.forEach(event => {
|
||||
eventsHtml += `<span class="input-group-addon pointer"
|
||||
data-myparam="${codeName}"
|
||||
data-myparam-plugin="${group}"
|
||||
data-myevent="${event}"
|
||||
onclick="handleEvent(this)"
|
||||
onclick="addToExecutionQueue(this)"
|
||||
>
|
||||
<i title="${getString(event + "_event_tooltip")}" class="fa ${getString(event + "_event_icon")}">
|
||||
</i>
|
||||
@@ -709,39 +842,50 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
|
||||
modalEventStatusId = 'modal-message-front-event'
|
||||
|
||||
function handleEvent (element){
|
||||
// --------------------------------------------------------
|
||||
// Calls a backend function to add a front-end event (specified by the attributes 'data-myevent' and 'data-myparam-plugin' on the passed element) to an execution queue
|
||||
function addToExecutionQueue(element)
|
||||
{
|
||||
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
value = $(element).attr('data-myevent') + '|'+ $(element).attr('data-myparam-plugin')
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
action = `${getGuid()}|${$(element).attr('data-myevent')}|${$(element).attr('data-myparam-plugin')}`
|
||||
|
||||
setParameter ('Front_Event', value)
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "php/server/util.php",
|
||||
data: { function: "addToExecutionQueue", action: action },
|
||||
success: function(data, textStatus) {
|
||||
// showModalOk ('Result', data );
|
||||
|
||||
// show message
|
||||
showModalOk("<?= lang("general_event_title")?>", "<?= lang("general_event_description")?> <code id='"+modalEventStatusId+"'></code>");
|
||||
|
||||
// Periodically update state of the requested action
|
||||
getParam(modalEventStatusId,"Front_Event", true, updateModalState)
|
||||
|
||||
updateModalState()
|
||||
}
|
||||
|
||||
|
||||
function updateModalState(){
|
||||
|
||||
setTimeout(function(){
|
||||
displayedEvent = $('#'+modalEventStatusId).html()
|
||||
|
||||
// loop until finished
|
||||
if(displayedEvent.indexOf('finished') == -1) // if the message is different from finished, check again in 2s
|
||||
{
|
||||
|
||||
getParam(modalEventStatusId,"Front_Event", true)
|
||||
// show message
|
||||
showModalOk(getString("general_event_title"), `${getString("general_event_description")} <br/> <br/> <code id='${modalEventStatusId}'></code>`);
|
||||
|
||||
updateModalState()
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Updating the execution queue in in modal pop-up
|
||||
function updateModalState() {
|
||||
setTimeout(function() {
|
||||
// Fetch the content from the log file using an AJAX request
|
||||
$.ajax({
|
||||
url: '/log/execution_queue.log',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
// Update the content of the HTML element (e.g., a div with id 'logContent')
|
||||
$('#'+modalEventStatusId).html(data);
|
||||
|
||||
updateModalState();
|
||||
},
|
||||
error: function() {
|
||||
// Handle error, such as the file not being found
|
||||
$('#logContent').html('Error: Log file not found.');
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -749,8 +893,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Show last time settings have been imported
|
||||
// getParam("lastImportedTime", "Back_Settings_Imported", skipCache = true);
|
||||
// Show last time settings have been imported
|
||||
|
||||
handleLoadingDialog()
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@ server {
|
||||
listen 80 default_server;
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
rewrite /pialert/(.*) / permanent;
|
||||
#rewrite /pialert/(.*) / permanent;
|
||||
add_header X-Forwarded-Prefix "/pialert" always;
|
||||
proxy_set_header X-Forwarded-Prefix "/pialert";
|
||||
|
||||
location ~* \.php$ {
|
||||
set $php_version "7.4"; # Default PHP version
|
||||
|
||||
# Use the selected PHP version
|
||||
fastcgi_pass unix:/run/php/php$php_version-fpm.sock;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_connect_timeout 75;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_read_timeout 600;
|
||||
}
|
||||
location ~* \.php$ {
|
||||
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_connect_timeout 75;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_read_timeout 600;
|
||||
}
|
||||
}
|
||||
49567
install/ieee-oui.txt
Executable file
49567
install/ieee-oui.txt
Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,98 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run install.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
# Set environment variables
|
||||
INSTALL_DIR=/home/pi # Specify the installation directory here
|
||||
|
||||
# Check if script is run as root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root. Please use 'sudo'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set environment variables
|
||||
PORT=20211
|
||||
INSTALL_DIR=/home/pi # Specify the installation directory here
|
||||
|
||||
# Update and upgrade system packages
|
||||
# apt-get update
|
||||
# apt-get upgrade -y
|
||||
# Prepare the environment
|
||||
apt-get update
|
||||
apt-get install sudo -y
|
||||
|
||||
# Install Git
|
||||
apt-get install -y git
|
||||
|
||||
# Clean the directory
|
||||
rm -R $INSTALL_DIR/pialert
|
||||
|
||||
# Clone the application repository
|
||||
git clone https://github.com/jokob-sk/Pi.Alert "$INSTALL_DIR/pialert"
|
||||
|
||||
# Install dependencies
|
||||
apt-get install -y \
|
||||
tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \
|
||||
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \
|
||||
python3 iproute2 nmap python3-pip zip systemctl usbutils traceroute
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# alternate dependencies
|
||||
sudo apt-get install -y \
|
||||
nginx nginx-core mtr mtr-tiny php-fpm php7.4-fpm
|
||||
|
||||
sudo apt install php-cli php7.4 php7.4-fpm -y
|
||||
sudo apt install php7.4-sqlite3 -y
|
||||
|
||||
sudo phpenmod -v 7.4 sqlite3
|
||||
sudo apt install net-tools -y
|
||||
|
||||
curl -sSL https://bootstrap.pypa.io/get-pip.py | python3
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
# Install Python packages
|
||||
pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi
|
||||
|
||||
# Update alternatives for Python
|
||||
update-alternatives --install /usr/bin/python python /usr/bin/python3 10
|
||||
|
||||
# Configure Nginx
|
||||
echo "Configure Nginx"
|
||||
echo "---------------------------------------------------------------"
|
||||
|
||||
|
||||
sudo rm -R /var/www/html
|
||||
ln -s $INSTALL_DIR/pialert/front /var/www/html
|
||||
sudo rm /etc/nginx/sites-available/default
|
||||
sudo ln -s "$INSTALL_DIR/pialert/install/default" /etc/nginx/sites-available/default
|
||||
sudo sed -i 's/listen 80/listen '"$PORT"'/g' /etc/nginx/sites-available/default
|
||||
|
||||
echo "Run the hardware vendors update"
|
||||
echo "---------------------------------------------------------------"
|
||||
# Run the hardware vendors update
|
||||
"$INSTALL_DIR/pialert/back/update_vendors.sh"
|
||||
|
||||
# Create a backup of pialert.conf
|
||||
cp "$INSTALL_DIR/pialert/config/pialert.conf" "$INSTALL_DIR/pialert/back/pialert.conf_bak"
|
||||
|
||||
# Create a backup of pialert.db
|
||||
cp "$INSTALL_DIR/pialert/db/pialert.db" "$INSTALL_DIR/pialert/back/pialert.db_bak"
|
||||
|
||||
# Create buildtimestamp.txt
|
||||
date +%s > "$INSTALL_DIR/pialert/front/buildtimestamp.txt"
|
||||
|
||||
chmod -R a+rwx $INSTALL_DIR
|
||||
chmod -R a+rwx /var/www/html
|
||||
chmod -R a+rw $INSTALL_DIR/front/log
|
||||
chmod -R a+rw $INSTALL_DIR/config
|
||||
|
||||
/etc/init.d/php7.4-fpm start
|
||||
# /etc/init.d/php8.2-fpm start
|
||||
/etc/init.d/nginx start
|
||||
|
||||
# Start Nginx and your application to start at boot (if needed)
|
||||
systemctl start nginx
|
||||
systemctl enable nginx
|
||||
systemctl enable pi-alert
|
||||
sudo systemctl restart nginx
|
||||
|
||||
# Provide instructions or additional setup if needed
|
||||
echo "Installation completed. Please configure any additional settings for your application."
|
||||
|
||||
|
||||
cd $INSTALL_DIR/pialert
|
||||
|
||||
# Start PiAlert
|
||||
"$INSTALL_DIR/pialert/dockerfiles/start.sh"
|
||||
|
||||
# Exit the script
|
||||
exit 0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user