Spaces:
Sleeping
Sleeping
Update app/internal_loads.py
Browse files- app/internal_loads.py +141 -127
app/internal_loads.py
CHANGED
@@ -25,6 +25,31 @@ from typing import Dict, List, Any, Optional, Tuple, Union
|
|
25 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
26 |
logger = logging.getLogger(__name__)
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
# Define constants
|
29 |
LOAD_TYPES = ["People", "Lighting", "Equipment", "Ventilation & Infiltration", "Schedules"]
|
30 |
|
@@ -923,16 +948,15 @@ def display_ventilation_infiltration_tab():
|
|
923 |
st.rerun()
|
924 |
|
925 |
def display_schedules_tab():
|
926 |
-
"""Display the schedules tab content with
|
|
|
|
|
927 |
# Split the display into two columns
|
928 |
col1, col2 = st.columns([3, 2])
|
929 |
|
930 |
with col1:
|
931 |
st.subheader("Saved Schedules")
|
932 |
-
|
933 |
-
# Get schedules from session state
|
934 |
schedules = st.session_state.project_data["internal_loads"]["schedules"]
|
935 |
-
|
936 |
if schedules:
|
937 |
display_schedules_table(schedules)
|
938 |
else:
|
@@ -941,140 +965,130 @@ def display_schedules_tab():
|
|
941 |
with col2:
|
942 |
st.subheader("Schedule Editor/Creator")
|
943 |
|
944 |
-
#
|
945 |
if "schedule_editor" not in st.session_state:
|
946 |
st.session_state.schedule_editor = {}
|
947 |
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
description
|
962 |
-
|
963 |
-
|
964 |
-
|
|
|
|
|
|
|
|
|
|
|
965 |
)
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
973 |
)
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
# Schedule values
|
978 |
-
st.write("**Hourly Schedule Values (0.0 - 1.0):**")
|
979 |
-
|
980 |
-
# Initialize schedule values
|
981 |
-
if template != "Custom" and not is_edit:
|
982 |
-
weekday_values = DEFAULT_SCHEDULE_TEMPLATES[template]["weekday"]
|
983 |
-
weekend_values = DEFAULT_SCHEDULE_TEMPLATES[template]["weekend"]
|
984 |
-
else:
|
985 |
-
weekday_values = editor_state.get("weekday", [0.0] * 24)
|
986 |
-
weekend_values = editor_state.get("weekend", [0.0] * 24)
|
987 |
-
|
988 |
-
# Weekday schedule
|
989 |
-
st.write("**Weekday Schedule:**")
|
990 |
-
weekday_cols = st.columns(6)
|
991 |
-
weekday_schedule = []
|
992 |
-
|
993 |
-
for hour in range(24):
|
994 |
-
col_idx = hour % 6
|
995 |
-
with weekday_cols[col_idx]:
|
996 |
-
value = st.number_input(
|
997 |
-
f"H{hour:02d}",
|
998 |
-
min_value=0.0,
|
999 |
-
max_value=1.0,
|
1000 |
-
value=float(weekday_values[hour]),
|
1001 |
-
format="%.2f",
|
1002 |
-
key=f"weekday_{hour}",
|
1003 |
-
help=f"Hour {hour}:00 weekday value"
|
1004 |
-
)
|
1005 |
-
weekday_schedule.append(value)
|
1006 |
-
|
1007 |
-
# Weekend schedule
|
1008 |
-
st.write("**Weekend Schedule:**")
|
1009 |
-
weekend_cols = st.columns(6)
|
1010 |
-
weekend_schedule = []
|
1011 |
-
|
1012 |
-
for hour in range(24):
|
1013 |
-
col_idx = hour % 6
|
1014 |
-
with weekend_cols[col_idx]:
|
1015 |
-
value = st.number_input(
|
1016 |
-
f"H{hour:02d}",
|
1017 |
-
min_value=0.0,
|
1018 |
-
max_value=1.0,
|
1019 |
-
value=float(weekend_values[hour]),
|
1020 |
-
format="%.2f",
|
1021 |
-
key=f"weekend_{hour}",
|
1022 |
-
help=f"Hour {hour}:00 weekend value"
|
1023 |
-
)
|
1024 |
-
weekend_schedule.append(value)
|
1025 |
-
|
1026 |
-
# Submit buttons
|
1027 |
-
col1, col2 = st.columns(2)
|
1028 |
-
with col1:
|
1029 |
-
submit_label = "Update Schedule" if is_edit else "Add Schedule"
|
1030 |
-
submit = st.form_submit_button(submit_label)
|
1031 |
-
|
1032 |
-
with col2:
|
1033 |
-
cancel = st.form_submit_button("Cancel")
|
1034 |
|
1035 |
-
#
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
st.
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
"
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1054 |
|
1055 |
-
#
|
1056 |
-
if
|
1057 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1058 |
|
1059 |
-
|
1060 |
-
st.
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
# Clear editor state
|
1067 |
st.session_state.schedule_editor = {}
|
1068 |
-
# [FIX]: Use module_rerun_flags instead of internal_loads_rerun_pending
|
1069 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
1070 |
st.rerun()
|
1071 |
-
|
1072 |
-
if cancel:
|
1073 |
-
# Clear editor state
|
1074 |
-
st.session_state.schedule_editor = {}
|
1075 |
-
# [FIX]: Use module_rerun_flags instead of internal_loads_rerun_pending
|
1076 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
1077 |
-
st.rerun()
|
1078 |
|
1079 |
def is_schedule_in_use(schedule_name: str) -> bool:
|
1080 |
"""
|
|
|
25 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
26 |
logger = logging.getLogger(__name__)
|
27 |
|
28 |
+
# Custom CSS for vertical sliders
|
29 |
+
st.markdown("""
|
30 |
+
<style>
|
31 |
+
.slider-container {
|
32 |
+
display: flex;
|
33 |
+
flex-direction: row;
|
34 |
+
align-items: flex-end;
|
35 |
+
justify-content: center;
|
36 |
+
gap: 8px;
|
37 |
+
padding-top: 30px;
|
38 |
+
}
|
39 |
+
.slider-item {
|
40 |
+
writing-mode: bt-lr;
|
41 |
+
transform: rotate(-90deg);
|
42 |
+
height: 150px;
|
43 |
+
width: 30px;
|
44 |
+
}
|
45 |
+
.hour-label {
|
46 |
+
text-align: center;
|
47 |
+
font-size: 12px;
|
48 |
+
margin-top: 5px;
|
49 |
+
}
|
50 |
+
</style>
|
51 |
+
""", unsafe_allow_html=True)
|
52 |
+
|
53 |
# Define constants
|
54 |
LOAD_TYPES = ["People", "Lighting", "Equipment", "Ventilation & Infiltration", "Schedules"]
|
55 |
|
|
|
948 |
st.rerun()
|
949 |
|
950 |
def display_schedules_tab():
|
951 |
+
"""Display the schedules tab content with responsive vertical slider interface."""
|
952 |
+
st.subheader("Schedule Management")
|
953 |
+
|
954 |
# Split the display into two columns
|
955 |
col1, col2 = st.columns([3, 2])
|
956 |
|
957 |
with col1:
|
958 |
st.subheader("Saved Schedules")
|
|
|
|
|
959 |
schedules = st.session_state.project_data["internal_loads"]["schedules"]
|
|
|
960 |
if schedules:
|
961 |
display_schedules_table(schedules)
|
962 |
else:
|
|
|
965 |
with col2:
|
966 |
st.subheader("Schedule Editor/Creator")
|
967 |
|
968 |
+
# Initialize editor state
|
969 |
if "schedule_editor" not in st.session_state:
|
970 |
st.session_state.schedule_editor = {}
|
971 |
|
972 |
+
editor_state = st.session_state.get("schedule_editor", {})
|
973 |
+
is_edit = editor_state.get("is_edit", False)
|
974 |
+
|
975 |
+
# Schedule name and description
|
976 |
+
name = st.text_input(
|
977 |
+
"Schedule Name",
|
978 |
+
value=editor_state.get("name", ""),
|
979 |
+
help="Enter a unique name for this schedule."
|
980 |
+
)
|
981 |
+
|
982 |
+
description = st.text_area(
|
983 |
+
"Description",
|
984 |
+
value=editor_state.get("description", ""),
|
985 |
+
help="Brief description of this schedule."
|
986 |
+
)
|
987 |
+
|
988 |
+
# Template selection for new schedules
|
989 |
+
if not is_edit:
|
990 |
+
template = st.selectbox(
|
991 |
+
"Start from Template",
|
992 |
+
["Custom"] + list(DEFAULT_SCHEDULE_TEMPLATES.keys()),
|
993 |
+
help="Select a template to start with, or choose Custom for blank schedule."
|
994 |
)
|
995 |
+
else:
|
996 |
+
template = "Custom"
|
997 |
+
|
998 |
+
# Initialize schedule values
|
999 |
+
if template != "Custom" and not is_edit:
|
1000 |
+
weekday_values = DEFAULT_SCHEDULE_TEMPLATES[template]["weekday"]
|
1001 |
+
weekend_values = DEFAULT_SCHEDULE_TEMPLATES[template]["weekend"]
|
1002 |
+
else:
|
1003 |
+
weekday_values = editor_state.get("weekday", [0.0] * 24)
|
1004 |
+
weekend_values = editor_state.get("weekend", [0.0] * 24)
|
1005 |
+
|
1006 |
+
# Weekday schedule
|
1007 |
+
st.write("**Weekday Schedule**")
|
1008 |
+
st.markdown('<div class="slider-container">', unsafe_allow_html=True)
|
1009 |
+
weekday_schedule = []
|
1010 |
+
for hour in range(24):
|
1011 |
+
with st.container():
|
1012 |
+
val = st.slider(
|
1013 |
+
label=f"{hour:02d}:00",
|
1014 |
+
min_value=0.0,
|
1015 |
+
max_value=1.0,
|
1016 |
+
step=0.01,
|
1017 |
+
value=float(weekday_values[hour]),
|
1018 |
+
key=f"weekday_{hour}",
|
1019 |
+
help=f"Hour {hour}:00 weekday value",
|
1020 |
+
format="%.2f"
|
1021 |
)
|
1022 |
+
st.markdown(f'<div class="hour-label">{hour:02d}:00</div>', unsafe_allow_html=True)
|
1023 |
+
weekday_schedule.append(val)
|
1024 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1025 |
|
1026 |
+
# Weekend schedule
|
1027 |
+
st.write("**Weekend Schedule**")
|
1028 |
+
st.markdown('<div class="slider-container">', unsafe_allow_html=True)
|
1029 |
+
weekend_schedule = []
|
1030 |
+
for hour in range(24):
|
1031 |
+
with st.container():
|
1032 |
+
val = st.slider(
|
1033 |
+
label=f"{hour:02d}:00",
|
1034 |
+
min_value=0.0,
|
1035 |
+
max_value=1.0,
|
1036 |
+
step=0.01,
|
1037 |
+
value=float(weekend_values[hour]),
|
1038 |
+
key=f"weekend_{hour}",
|
1039 |
+
help=f"Hour {hour}:00 weekend value",
|
1040 |
+
format="%.2f"
|
1041 |
+
)
|
1042 |
+
st.markdown(f'<div class="hour-label">{hour:02d}:00</div>', unsafe_allow_html=True)
|
1043 |
+
weekend_schedule.append(val)
|
1044 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
1045 |
+
|
1046 |
+
# Preview chart
|
1047 |
+
st.write("**Schedule Preview**")
|
1048 |
+
display_schedule_chart(f"Preview: {name or 'New Schedule'}", {
|
1049 |
+
"weekday": weekday_schedule,
|
1050 |
+
"weekend": weekend_schedule
|
1051 |
+
})
|
1052 |
+
|
1053 |
+
# Action buttons
|
1054 |
+
col1, col2 = st.columns(2)
|
1055 |
+
with col1:
|
1056 |
+
submit_label = "Update Schedule" if is_edit else "Add Schedule"
|
1057 |
+
if st.button(submit_label):
|
1058 |
+
# Validate inputs
|
1059 |
+
if not name.strip():
|
1060 |
+
st.error("Schedule name is required.")
|
1061 |
+
elif name in schedules and not is_edit:
|
1062 |
+
st.error("A schedule with this name already exists.")
|
1063 |
+
else:
|
1064 |
+
# Create schedule data
|
1065 |
+
schedule_data = {
|
1066 |
+
"description": description,
|
1067 |
+
"weekday": weekday_schedule,
|
1068 |
+
"weekend": weekend_schedule
|
1069 |
+
}
|
1070 |
|
1071 |
+
# Update or add schedule
|
1072 |
+
if is_edit and st.session_state.schedule_editor.get("original_name"):
|
1073 |
+
original_name = st.session_state.schedule_editor["original_name"]
|
1074 |
+
if original_name != name and original_name in schedules:
|
1075 |
+
del schedules[original_name]
|
1076 |
+
schedules[name] = schedule_data
|
1077 |
+
st.success(f"Schedule '{name}' updated successfully!")
|
1078 |
+
else:
|
1079 |
+
schedules[name] = schedule_data
|
1080 |
+
st.success(f"Schedule '{name}' added successfully!")
|
1081 |
|
1082 |
+
# Clear editor state
|
1083 |
+
st.session_state.schedule_editor = {}
|
1084 |
+
st.session_state.module_rerun_flags["internal_loads"] = True
|
1085 |
+
st.rerun()
|
1086 |
+
|
1087 |
+
with col2:
|
1088 |
+
if st.button("Cancel"):
|
|
|
1089 |
st.session_state.schedule_editor = {}
|
|
|
1090 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
1091 |
st.rerun()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1092 |
|
1093 |
def is_schedule_in_use(schedule_name: str) -> bool:
|
1094 |
"""
|