Notifications refactor and #242 📩

This commit is contained in:
Jokob-sk
2023-12-17 22:43:50 +11:00
parent 911c897b00
commit 8e0eb6a480
11 changed files with 296 additions and 91 deletions

View File

@@ -161,22 +161,9 @@ def main ():
if notificationObj.HasNotifications:
pluginsState = run_plugin_scripts(db, 'on_notification', pluginsState)
notification.setAllProcessed()
notification.clearPendingEmailFlag()
# Clean Pending Alert Events
sql.execute ("""UPDATE Devices SET dev_LastNotification = ?
WHERE dev_MAC IN (
SELECT eve_MAC FROM Events
WHERE eve_PendingAlertEmail = 1
)
""", (timeNowTZ(),) )
sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1""")
# clear plugin events
sql.execute ("DELETE FROM Plugins_Events")
# DEBUG - print number of rows updated
mylog('minimal', ['[Notification] Notifications changes: ', sql.rowcount])
else:
mylog('verbose', ['[Notification] No changes to report'])

View File

@@ -41,8 +41,8 @@ def print_scan_stats(db):
SELECT
(SELECT COUNT(*) FROM CurrentScan) AS devices_detected,
(SELECT COUNT(*) FROM CurrentScan WHERE NOT EXISTS (SELECT 1 FROM Devices WHERE dev_MAC = cur_MAC)) AS new_devices,
(SELECT COUNT(*) FROM Devices WHERE dev_AlertDeviceDown = 1 AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC)) AS down_alerts,
(SELECT COUNT(*) FROM Devices WHERE dev_AlertDeviceDown = 1 AND dev_PresentLastScan = 1 AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC)) AS new_down_alerts,
(SELECT COUNT(*) FROM Devices WHERE dev_AlertDeviceDown != 0 AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC)) AS down_alerts,
(SELECT COUNT(*) FROM Devices WHERE dev_AlertDeviceDown != 0 AND dev_PresentLastScan = 1 AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC)) AS new_down_alerts,
(SELECT COUNT(*) FROM Devices WHERE dev_PresentLastScan = 0) AS new_connections,
(SELECT COUNT(*) FROM Devices WHERE dev_PresentLastScan = 1 AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC)) AS disconnections,
(SELECT COUNT(*) FROM Devices, CurrentScan WHERE dev_MAC = cur_MAC AND dev_LastIP <> cur_IP) AS ip_changes,

View File

@@ -37,6 +37,12 @@ def timeNowTZ():
def timeNow():
return datetime.datetime.now().replace(microsecond=0)
def get_timezone_offset():
now = datetime.datetime.now(conf.tz)
offset_hours = now.utcoffset().total_seconds() / 3600
offset_formatted = "{:+03d}:{:02d}".format(int(offset_hours), int((offset_hours % 1) * 60))
return offset_formatted
#-------------------------------------------------------------------------------
# App state
@@ -470,58 +476,6 @@ def resolve_device_name_pholus (pMAC, pIP, allRes, nameNotFound, match_IP = Fals
if 'PTR Class:IN' in value and len(value.split('"')) > 1:
return cleanDeviceName(value.split('"')[1], match_IP)
# # airplay matches contain a lot of information
# # Matches for example:
# # Brand Tv (50)._airplay._tcp.local. TXT Class:32769 "acl=0 deviceid=66:66:66:66:66:66 features=0x77777,0x38BCB46 rsf=0x3 fv=p20.T-FFFFFF-03.1 flags=0x204 model=XXXX manufacturer=Brand serialNumber=XXXXXXXXXXX protovers=1.1 srcvers=777.77.77 pi=FF:FF:FF:FF:FF:FF psi=00000000-0000-0000-0000-FFFFFFFFFF gid=00000000-0000-0000-0000-FFFFFFFFFF gcgl=0 pk=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and '._airplay._tcp.local. TXT Class:32769' in str(allRes[i]["Value"]) :
# return cleanDeviceName(allRes[i]["Value"].split('._airplay._tcp.local. TXT Class:32769')[0], match_IP)
# # second best - contains airplay
# # Matches for example:
# # _airplay._tcp.local. PTR Class:IN "Brand Tv (50)._airplay._tcp.local."
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and '_airplay._tcp.local. PTR Class:IN' in allRes[i]["Value"] and ('._googlecast') not in allRes[i]["Value"]:
# return cleanDeviceName(allRes[i]["Value"].split('"')[1], match_IP)
# # Contains PTR Class:32769
# # Matches for example:
# # 3.1.168.192.in-addr.arpa. PTR Class:32769 "MyPc.local."
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and 'PTR Class:32769' in allRes[i]["Value"]:
# return cleanDeviceName(allRes[i]["Value"].split('"')[1], match_IP)
# # Contains AAAA Class:IN
# # Matches for example:
# # DESKTOP-SOMEID.local. AAAA Class:IN "fe80::fe80:fe80:fe80:fe80"
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and 'AAAA Class:IN' in allRes[i]["Value"]:
# return cleanDeviceName(allRes[i]["Value"].split('.local.')[0], match_IP)
# # Contains _googlecast._tcp.local. PTR Class:IN
# # Matches for example:
# # _googlecast._tcp.local. PTR Class:IN "Nest-Audio-ff77ff77ff77ff77ff77ff77ff77ff77._googlecast._tcp.local."
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and '_googlecast._tcp.local. PTR Class:IN' in allRes[i]["Value"] and ('Google-Cast-Group') not in allRes[i]["Value"]:
# return cleanDeviceName(allRes[i]["Value"].split('"')[1], match_IP)
# # Contains A Class:32769
# # Matches for example:
# # Android.local. A Class:32769 "192.168.1.6"
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and ' A Class:32769' in allRes[i]["Value"]:
# return cleanDeviceName(allRes[i]["Value"].split(' A Class:32769')[0], match_IP)
# # # Contains PTR Class:IN
# # Matches for example:
# # _esphomelib._tcp.local. PTR Class:IN "ceiling-light-1._esphomelib._tcp.local."
# for i in pholusMatchesIndexes:
# if checkIPV4(allRes[i]['IP_v4_or_v6']) and 'PTR Class:IN' in allRes[i]["Value"]:
# if allRes[i]["Value"] and len(allRes[i]["Value"].split('"')) > 1:
# return cleanDeviceName(allRes[i]["Value"].split('"')[1], match_IP)
return nameNotFound

View File

@@ -187,7 +187,7 @@ def insert_events (db):
eve_PendingAlertEmail)
SELECT dev_MAC, dev_LastIP, '{startTime}', 'Device Down', '', 1
FROM Devices
WHERE dev_AlertDeviceDown = 1
WHERE dev_AlertDeviceDown != 0
AND dev_PresentLastScan = 1
AND NOT EXISTS (SELECT 1 FROM CurrentScan
WHERE dev_MAC = cur_MAC

View File

@@ -10,7 +10,7 @@ import conf
import const
from const import pialertPath, logPath, apiPath
from logger import logResult, mylog, print_log
from helper import generate_mac_links, removeDuplicateNewLines, timeNowTZ, get_file_content, write_file
from helper import generate_mac_links, removeDuplicateNewLines, timeNowTZ, get_file_content, write_file, get_setting_value, get_timezone_offset
#-------------------------------------------------------------------------------
# Notification object handling
@@ -209,7 +209,34 @@ class Notification_obj:
self.save()
def clearPendingEmailFlag(self):
# Clean Pending Alert Events
self.db.sql.execute ("""UPDATE Devices SET dev_LastNotification = ?
WHERE dev_MAC IN (
SELECT eve_MAC FROM Events
WHERE eve_PendingAlertEmail = 1
)
""", (timeNowTZ(),) )
self.db.sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType !='Device Down' """)
# Clear down events flag after the reporting window passed
self.db.sql.execute (f"""UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType =='Device Down'
AND eve_DateTime < datetime('now', '-{get_setting_value('NTFPRCS_alert_down_time')} minutes', '{get_timezone_offset()}')
""")
# clear plugin events
self.db.sql.execute ("DELETE FROM Plugins_Events")
# DEBUG - print number of rows updated
mylog('minimal', ['[Notification] Notifications changes: ', self.db.sql.rowcount])
self.save()
def save(self):
# Commit changes

View File

@@ -17,7 +17,7 @@ import json
import conf
import const
from const import pialertPath, logPath, apiPath
from helper import timeNowTZ, get_file_content, write_file
from helper import timeNowTZ, get_file_content, write_file, get_timezone_offset, get_setting_value
from logger import logResult, mylog, print_log
@@ -74,10 +74,21 @@ def get_notifications (db):
if 'down_devices' in conf.INCLUDED_SECTIONS :
# Compose Devices Down Section
sqlQuery = """SELECT eve_MAC as MAC, eve_DateTime as Datetime, dev_LastIP as IP, eve_EventType as "Event Type", dev_Name as "Device name", dev_Comments as Comments FROM Events_Devices
WHERE eve_PendingAlertEmail = 1
AND eve_EventType = 'Device Down'
ORDER BY eve_DateTime"""
sqlQuery = f"""
SELECT *
FROM Events AS down_events
WHERE eve_PendingAlertEmail = 1
AND down_events.eve_EventType = 'Device Down'
AND eve_DateTime < datetime('now', '-{get_setting_value('NTFPRCS_alert_down_time')} minutes', '{get_timezone_offset()}')
AND NOT EXISTS (
SELECT 1
FROM Events AS connected_events
WHERE connected_events.eve_MAC = down_events.eve_MAC
AND connected_events.eve_EventType = 'Connected'
AND connected_events.eve_DateTime > down_events.eve_DateTime
)
ORDER BY down_events.eve_DateTime;
"""
# Get the events as JSON
json_obj = db.get_table_as_json(sqlQuery)
@@ -139,7 +150,8 @@ def skip_repeated_notifications (db):
# Skip repeated notifications
# due strfime : Overflow --> use "strftime / 60"
mylog('verbose','[Skip Repeated Notifications] Skip Repeated start')
mylog('verbose','[Skip Repeated Notifications] Skip Repeated')
db.sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1 AND eve_MAC IN
(
@@ -151,7 +163,7 @@ def skip_repeated_notifications (db):
(strftime('%s','now','localtime')/60 )
)
""" )
mylog('verbose','[Skip Repeated Notifications] Skip Repeated end')
db.commitDB()