147 lines
5.6 KiB
Python
147 lines
5.6 KiB
Python
import dash
|
|
from dash import dcc, html, Input, Output, State
|
|
import plotly.express as px
|
|
import sqlite3
|
|
import pandas as pd
|
|
from datetime import datetime, timedelta
|
|
|
|
# Create a Dash app
|
|
app = dash.Dash(__name__)
|
|
|
|
# Function to fetch data from the SQLite database
|
|
def fetch_data():
|
|
conn = sqlite3.connect('power_data.db')
|
|
building_totals = pd.read_sql_query('SELECT * FROM building_totals', conn)
|
|
room_breakdown = pd.read_sql_query('SELECT * FROM room_breakdown', conn)
|
|
conn.close()
|
|
return building_totals, room_breakdown
|
|
|
|
# Function to calculate kWh usage
|
|
def calculate_kwh(data, power_column):
|
|
data = data.copy() # Create a copy of the DataFrame to avoid SettingWithCopyWarning
|
|
data.loc[:, 'timestamp'] = pd.to_datetime(data['timestamp'], format='ISO8601')
|
|
data = data.sort_values('timestamp')
|
|
data.loc[:, 'time_diff'] = data['timestamp'].diff().dt.total_seconds() / 3600 # Convert to hours
|
|
data.loc[:, 'kwh'] = data[power_column] * data['time_diff']
|
|
data.loc[:, 'cumulative_kwh'] = data['kwh'].cumsum()
|
|
return data
|
|
|
|
# Define the layout of the dashboard
|
|
app.layout = html.Div([
|
|
html.H1("Power and Current Data Dashboard"),
|
|
dcc.Dropdown(
|
|
id='time-range-selector',
|
|
options=[
|
|
{'label': 'Last 6 Hours', 'value': 6},
|
|
{'label': 'Last 12 Hours', 'value': 12},
|
|
{'label': 'Last 1 Day', 'value': 24},
|
|
{'label': 'Last 2 Days', 'value': 48},
|
|
{'label': 'Last 1 Week', 'value': 168},
|
|
{'label': 'Last 1 Month', 'value': 720},
|
|
{'label': 'Last 2 Months', 'value': 1440},
|
|
{'label': 'Last 1 Year', 'value': 8760}
|
|
],
|
|
value=6,
|
|
clearable=False
|
|
),
|
|
dcc.Graph(id='building-totals-graph'),
|
|
dcc.Dropdown(
|
|
id='room-selector',
|
|
options=[{'label': room, 'value': room} for room in fetch_data()[1]['room_number'].unique()],
|
|
value=None,
|
|
placeholder="Select a room"
|
|
),
|
|
dcc.Graph(id='room-graph')
|
|
])
|
|
|
|
# Define callbacks to update the graphs
|
|
@app.callback(
|
|
Output('building-totals-graph', 'figure'),
|
|
Input('time-range-selector', 'value'),
|
|
Input('building-totals-graph', 'relayoutData')
|
|
)
|
|
def update_building_totals_graph(time_range, relayoutData):
|
|
building_totals, _ = fetch_data()
|
|
building_totals = calculate_kwh(building_totals, 'total_power')
|
|
|
|
# Handle time range selection
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(hours=time_range)
|
|
filtered_data = building_totals[(building_totals['timestamp'] >= start_time) & (building_totals['timestamp'] <= end_time)]
|
|
|
|
# Handle zoom level
|
|
if relayoutData and 'xaxis.range[0]' in relayoutData:
|
|
zoom_start = pd.to_datetime(relayoutData['xaxis.range[0]'])
|
|
zoom_end = pd.to_datetime(relayoutData['xaxis.range[1]'])
|
|
filtered_data = filtered_data[(filtered_data['timestamp'] >= zoom_start) & (filtered_data['timestamp'] <= zoom_end)]
|
|
|
|
latest_data = filtered_data.iloc[-1] if not filtered_data.empty else None
|
|
|
|
fig = px.line(filtered_data, x='timestamp', y=['total_current', 'total_power', 'cumulative_kwh'],
|
|
title='Building Totals', labels={'value': 'Value', 'variable': 'Metric'})
|
|
|
|
if latest_data is not None:
|
|
fig.update_traces(
|
|
name=f"Total Current: {latest_data['total_current']} A",
|
|
selector=dict(name="total_current")
|
|
)
|
|
fig.update_traces(
|
|
name=f"Total Power: {latest_data['total_power']} kW",
|
|
selector=dict(name="total_power")
|
|
)
|
|
fig.update_traces(
|
|
name=f"Cumulative kWh: {round(latest_data['cumulative_kwh'], 3)} kWh",
|
|
selector=dict(name="cumulative_kwh")
|
|
)
|
|
|
|
return fig
|
|
|
|
@app.callback(
|
|
Output('room-graph', 'figure'),
|
|
Input('time-range-selector', 'value'),
|
|
Input('room-selector', 'value'),
|
|
Input('room-graph', 'relayoutData')
|
|
)
|
|
def update_room_graph(time_range, selected_room, relayoutData):
|
|
if selected_room:
|
|
_, room_breakdown = fetch_data()
|
|
room_data = room_breakdown[room_breakdown['room_number'] == selected_room]
|
|
room_data = calculate_kwh(room_data, 'power')
|
|
|
|
# Handle time range selection
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(hours=time_range)
|
|
filtered_data = room_data[(room_data['timestamp'] >= start_time) & (room_data['timestamp'] <= end_time)]
|
|
|
|
# Handle zoom level
|
|
if relayoutData and 'xaxis.range[0]' in relayoutData:
|
|
zoom_start = pd.to_datetime(relayoutData['xaxis.range[0]'])
|
|
zoom_end = pd.to_datetime(relayoutData['xaxis.range[1]'])
|
|
filtered_data = filtered_data[(filtered_data['timestamp'] >= zoom_start) & (filtered_data['timestamp'] <= zoom_end)]
|
|
|
|
latest_data = filtered_data.iloc[-1] if not filtered_data.empty else None
|
|
|
|
fig = px.line(filtered_data, x='timestamp', y=['current', 'power', 'cumulative_kwh'],
|
|
title=f'Room {selected_room}', labels={'value': 'Value', 'variable': 'Metric'})
|
|
|
|
if latest_data is not None:
|
|
fig.update_traces(
|
|
name=f"Current: {latest_data['current']} A",
|
|
selector=dict(name="current")
|
|
)
|
|
fig.update_traces(
|
|
name=f"Power: {latest_data['power']} kW",
|
|
selector=dict(name="power")
|
|
)
|
|
fig.update_traces(
|
|
name=f"Cumulative kWh: {round(latest_data['cumulative_kwh'], 3)} kWh",
|
|
selector=dict(name="cumulative_kwh")
|
|
)
|
|
|
|
return fig
|
|
return px.line(title='Select a room to display its graph')
|
|
|
|
# Run the app
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=8050, debug=True)
|