Hello guys,
I’m making an alarm notification application.The application is to run all the time in the background as checking the queries (machines).Only when the user changes the parameters and the alert recievers (emails) will the app make a change and according to those changes will continue checking the queries (machines) in the background. At the moment I have four machines in four tabs, but I need help connecting the backend, to the settings and to the queries and also that the app works in the background all the time.Also I’m using an api to get the emails, and also to add new users or deleting the current ones.
1.This is my UI.
I will explain for this machine br206.
For Alert 1 settings I need to:
BDE Downtime after and the time the user picks (for an example 15 minutes) and Select Downtime Receivers ( emails from api) need to be tied to the first button and then the app changes the checking of the Alert 1 settings in the background.
Scrap rate (for an example 3%) and Scrap Alert After (means after 15 mins if the scrap rate is still 3%) need to be tied to the second button that sents an email to one of the Select Scrap Receivers that the user picks (from the api).
This is my UI code:
dcc.Tabs(id='tabs', value='br206', children=[
dcc.Tab(label='BR206', value='br206', children=[
html.Div([html.H1("BR206 Alert Notifications", className='header-title'), # Centered header
html.Div([
# Alert 1 Settings
html.Div([
html.H3("Alert 1 Settings"),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom': '10px'}),
html.Div([
html.H3("BDE Downtime after:", className='dropdown-label'),
dcc.Dropdown(
id='br206-bde-connection-interval-dropdown-alert1',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown',
),
], className='bde-connection-interval', style={'margin-bottom': '10px'}),
html.H3("Select Downtime Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-downtime-employee-category-dropdown1',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button1-downtime', n_clicks=0, style={'margin-top': '10px'}),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom':'10px'}),
html.H3("Scrap Rate:", className='input-header'),
dcc.Dropdown(
id='br206-scrap-rate-input-alert1',
options=[{'label': f'{i}%', 'value': f'{i}%'} for i in range(1, 13)],
value='3%',
className='input-field',
style={'width': '150px', 'margin-left': '14px'}
),
html.H3("Scrap Alert After:", className='dropdown-label'),
dcc.Dropdown(
id='br206-scrap-connection-interval-dropdown-alert1',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown',
),
html.H3("Select Scrap Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-employee-category-dropdown-alert1',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
# Div to display employee names based on selected category
html.Div(id='br206-employee-list-alert1'),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button1-scrap', n_clicks=0, style={'margin-top': '10px'}),
], className='alert-box'),
], style={'margin': '20px', 'border': '1px solid #ddd', 'padding': '20px', 'display': 'inline-block'}),
# Alert 2 Settings
html.Div([
html.H3("Alert 2 Settings"),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom': '10px'}),
# BDE Connection interval dropdown
html.Div([
html.H3("BDE Downtime after:", className='dropdown-label'),
dcc.Dropdown(
id='br206-bde-connection-interval-dropdown-alert2',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown'
),
], className='bde-connection-interval'),
html.H3("Select Downtime Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-downtime-employee-category-dropdown2',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button2-downtime', n_clicks=0, style={'margin-top': '10px'}),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom': '10px'}),
html.H3("Scrap Rate:", className='input-header'),
dcc.Dropdown(
id='br206-scrap-rate-input-alert2',
options=[{'label': f'{i}%', 'value': f'{i}%'} for i in range(1, 13)],
value='3%',
className='input-field',
style={'width': '150px', 'margin-left': '14px'}
),
html.H3("Scrap Alert After:", className='dropdown-label'),
dcc.Dropdown(
id='br206-scrap-connection-interval-dropdown-alert2',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown',
),
html.H3("Select Scrap Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-employee-category-dropdown-alert2',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
# Div to display employee names based on selected category
html.Div(id='br206-employee-list-alert2'),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button2-scrap', n_clicks=0, style={'margin-top': '10px'})
], className='alert-box', style={'margin': '20px', 'border': '1px solid #ddd', 'padding': '20px', 'display': 'inline-block'}),
# Alert 3 Settings
html.Div([
html.H3("Alert 3 Settings"),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom': '10px'}),
# BDE Connection interval dropdown
html.Div([
html.H3("BDE Downtime after:", className='dropdown-label'),
dcc.Dropdown(
id='br206-bde-connection-interval-dropdown-alert3',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown'
),
], className='bde-connection-interval'),
html.H3("Select Downtime Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-downtime-employee-category-dropdown3',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button3-downtime', n_clicks=0, style={'margin-top': '10px'}),
html.Div(style={'border-top': '5px solid #ddd', 'margin-top': '10px', 'margin-bottom': '10px'}),
html.H3("Scrap Rate:", className='input-header'),
dcc.Dropdown(
id='br206-scrap-rate-input-alert3',
options=[{'label': f'{i}%', 'value': f'{i}%'} for i in range(1, 13)],
value='3%',
className='input-field',
style={'width': '150px', 'margin-left': '14px'}
),
html.H3("Scrap Alert After:", className='dropdown-label'),
dcc.Dropdown(
id='br206-scrap-connection-interval-dropdown-alert3',
options=generate_bde_connection_interval_options(),
value=15,
className='dropdown',
),
html.H3("Select Scrap Receivers:", className='dropdown-label'),
dcc.Dropdown(
id='br206-employee-category-dropdown-alert3',
options=[{'label': key, 'value': key} for key in employee_positions.keys()],
className='dropdown'
),
# Div to display employee names based on selected category
html.Div(id='br206-employee-list-alert3'),
html.Button('Make Changes', className='button' ,id='br206-make-changes-button3-scrap', n_clicks=0, style={'margin-top': '10px'}),
html.Button("Add New User", id="add-new-user-button1", className="btn btn-success button", n_clicks=0, style={'position': 'absolute', 'bottom': '150px', 'right': '1220px'}),
], className='alert-box', style={'margin': '20px', 'border': '1px solid #ddd', 'padding': '20px', 'display': 'inline-block'})
], style={'text-align': 'center'})
]),
I made all unique ID’s for all the settings and buttons, please keep in mind that I did this for all the machines and all the settings.
Now my backend code for BR206 Alert Settings 1 is
############################## Alert 1 Settings #####################################
# Callback to handle changes in Alert 1 Downtime settings br206
@app.callback(
Output('br206-output-alert1-downtime', 'children'),
[Input('br206-make-changes-button1-downtime', 'n_clicks')],
[State('br206-bde-connection-interval-dropdown-alert1', 'value'),
State('br206-downtime-employee-category-dropdown1', 'value')]
)
def br206_handle_alert1_downtime_changes(n_clicks, bde_interval, downtime_receivers):
if n_clicks > 0:
print("BDE Interval:", bde_interval)
print("Downtime Receivers:", downtime_receivers)
return "Changes saved successfully!"
# Callback to handle changes in Alert 1 Scrap settings br206
@app.callback(
Output('br206-output-alert1-scrap', 'children'),
[Input('br206-make-changes-button1-scrap', 'n_clicks')],
[State('br206-scrap-rate-input-alert1', 'value'),
State('br206-scrap-connection-interval-dropdown-alert1', 'value'),
State('br206-employee-category-dropdown-alert1', 'value')]
)
def br206_handle_alert1_scrap_changes(n_clicks, scrap_rate, scrap_interval, scrap_receivers):
if n_clicks > 0:
print("Scrap Rate:", scrap_rate)
print("Scrap Interval:", scrap_interval)
print("Scrap Receivers:", scrap_receivers)
# Return a message or confirmation
return "Changes saved successfully!"
############################## Alert 2 Settings #####################################
# Callback to handle changes in Alert 2 Downtime settings br206
@app.callback(
Output('br206-output-alert2-downtime', 'children'),
[Input('br206-make-changes-button2-downtime', 'n_clicks')],
[State('br206-bde-connection-interval-dropdown-alert2', 'value'),
State('br206-downtime-employee-category-dropdown2', 'value')]
)
def br206_handle_alert2_downtime_changes(n_clicks, bde_interval, downtime_receivers):
# Logic to save the selected parameters when the button is clicked
if n_clicks > 0:
# Save the selected BDE interval and downtime receivers
# You can perform any further processing or database updates here
print("BDE Interval:", bde_interval)
print("Downtime Receivers:", downtime_receivers)
return "Changes saved successfully!"
# Callback to handle changes in Alert 2 Scrap settings br206
@app.callback(
Output('br206-output-alert2-scrap', 'children'),
[Input('br206-make-changes-button2-scrap', 'n_clicks')],
[State('br206-scrap-rate-input-alert2', 'value'),
State('br206-scrap-connection-interval-dropdown-alert2', 'value'),
State('br206-employee-category-dropdown-alert2', 'value')]
)
def br206_handle_alert2_scrap_changes(n_clicks, scrap_rate, scrap_interval, scrap_receivers):
if n_clicks > 0:
print("Scrap Rate:", scrap_rate)
print("Scrap Interval:", scrap_interval)
print("Scrap Receivers:", scrap_receivers)
return "Changes saved successfully!"
############################## Alert 3 Settings #####################################
# Callback to handle changes in Alert 3 Downtime settings br206
@app.callback(
Output('br206-output-alert3-downtime', 'children'),
[Input('br206-make-changes-button3-downtime', 'n_clicks')],
[State('br206-bde-connection-interval-dropdown-alert3', 'value'),
State('br206-downtime-employee-category-dropdown3', 'value')]
)
def br206_handle_alert3_downtime_changes(n_clicks, bde_interval, downtime_receivers):
if n_clicks > 0:
print("BDE Interval:", bde_interval)
print("Downtime Receivers:", downtime_receivers)
# Return a message or confirmation
return "Changes saved successfully!"
# Callback to handle changes in Alert 3 Scrap settings br206
@app.callback(
Output('br206-output-alert3-scrap', 'children'),
[Input('br206-make-changes-button3-scrap', 'n_clicks')],
[State('br206-scrap-rate-input-alert3', 'value'),
State('br206-scrap-connection-interval-dropdown-alert3', 'value'),
State('br206-employee-category-dropdown-alert3', 'value')]
)
def br206_handle_alert3_scrap_changes(n_clicks, scrap_rate, scrap_interval, scrap_receivers):
if n_clicks > 0:
print("Scrap Rate:", scrap_rate)
print("Scrap Interval:", scrap_interval)
print("Scrap Receivers:", scrap_receivers)
return "Changes saved successfully!"
So from the UI to this backend code I need when I click the buttons “Make Changes” that the app reads the backend tied to the buttons and executes the new queries and starts sending the emails when something from the inputs happen, but I don’t know how to do it alone.
For an example:
When the downtime for br206 is 15 minutes it will send to alert 1 Users, but if the downtime is 30 minues (from Alert 2) it will then send to the Alert 2 emails, also if downtime is still happening after 120 minutes it will send the email to the Alert 3 emails.
Now for my semail sending code I have this:
def send_email(subject, message, to):
try:
outlook = win32com.client.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
# Email configuration
email = 'test@local'
mail.To = ', '.join(to)
mail.Subject = subject
mail.BCC = "test-mail"
# HTML body
mail.HTMLBody = message
mail.Send()
except Exception as e:
print(f"Error sending email: {str(e)}")
And this is a function that just test the connection every 30 mins and sends an email to the user.
def fetch_the_downtime():
# Define the end time (current time)
end_time = datetime.datetime.now()
# Define the start time (30 minutes ago)
start_time = end_time - datetime.timedelta(minutes=30)
# Define the time range strings
start_time_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
end_time_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
# Define the database configurations
databases = [
{"name": "ked33", "server": "ip ", "database": "ked33", "uid": "bde", "pwd": "pass"},
{"name": "br206", "server": "ip ", "database": "br206", "uid": "bde", "pwd": "pass"},
{"name": "GSL-1 BAT", "server": "ip ", "database": "GSL-1 BAT", "uid": "BAT", "pwd": "pass"},
{"name": "GSL-2 SUSO", "server": "ip ", "database": "GSL-2 SUSO", "uid": "BAT", "pwd": "pass"}
]
# Iterate over each database configuration
for db_info in databases:
conn = None # Initialize connection variable
try:
# Establish a connection to the database
conn = pyodbc.connect(
f"DRIVER={{ODBC Driver 18 for SQL Server}};"
f"SERVER={db_info['server']};"
f"DATABASE={db_info['database']};"
f"UID={db_info['uid']};"
f"PWD={db_info['pwd']};"
"TrustServerCertificate=yes"
)
# Define the SQL query to fetch downtime occurrences
query = f'''
SELECT COUNT(*) AS total_downtime
FROM [{db_info['database']}].[dbo].[NotificationLog]
WHERE [Timestamp] BETWEEN '{start_time_str}' AND '{end_time_str}' AND [Duration] > 3600
'''
# Execute the query
cursor = conn.cursor()
cursor.execute(query)
# Fetch the result
result = cursor.fetchone()
# Check if result is not None and if there are any downtime occurrences
if result and result[0] > 0:
# Send email notification
subject = f"{db_info['name']} downtime detected"
message = f"{result[0]} downtime occurrence(s) with duration over 3600 seconds detected in the last 30 minutes."
send_email(subject, message, [test@mail.com'])
print(f"Downtime check for {db_info['name']} completed at {end_time}")
except Exception as e:
# Handle any exceptions
print(f"Error for {db_info['name']}: {str(e)}")
finally:
# Close the database connection
if conn:
conn.close()
schedule.every(30).minutes.do(fetch_the_downtime)
Also I made for bde downtime
def generate_bde_connection_interval_options():
return [
{'label': '15 min', 'value': 15},
{'label': '30 min', 'value': 30},
{'label': '60 min', 'value': 60},
{'label': '120 min', 'value': 120}
]
but for scrap I did:
dcc.Dropdown(
id='br206-scrap-rate-input-alert1',
options=[{'label': f'{i}%', 'value': f'{i}%'} for i in range(1, 13)],
value='3%',
className='input-field',
style={'width': '150px', 'margin-left': '14px'}
),
should I do it like I did for downtime? so the query will pick up the setting?
Now what I need help is making this
When the downtime for br206 is 15 minutes it will send to alert 1 Users, but if the downtime is 30 minues (from Alert 2) it will then send to the Alert 2 emails, also if downtime is still happening after 120 minutes it will send the email to the Alert 3 emails.
So I need queries like that one that will take the user inputs, save them, check them all the time in the background and if thet alert setting happens then it will send the email to the ones that the user picked up from the api options.
Also that it is all connected to the ui trough the callbacks that I made.
I think I just need one Alert setting to work, then the rest would be the same just different ID’s.
Also I made for bde downtime
Thank you.