Spaces:
Sleeping
Sleeping
Update app/internal_loads.py
Browse files- app/internal_loads.py +81 -87
app/internal_loads.py
CHANGED
@@ -927,51 +927,63 @@ def display_schedules_tab():
|
|
927 |
"""
|
928 |
Display the schedules tab content with vertical sliders for hourly schedules.
|
929 |
"""
|
|
|
|
|
|
|
930 |
st.subheader("Schedules Editor")
|
931 |
|
932 |
-
# Initialise editor state
|
933 |
if "schedule_editor" not in st.session_state:
|
934 |
st.session_state.schedule_editor = {}
|
935 |
|
|
|
|
|
|
|
936 |
editor_state = st.session_state.schedule_editor
|
937 |
is_edit = editor_state.get("is_edit", False)
|
938 |
|
939 |
-
#
|
940 |
-
|
941 |
-
"Schedule Name",
|
942 |
-
value=editor_state.get("name", ""),
|
943 |
-
help="Enter a unique name for this schedule."
|
944 |
-
)
|
945 |
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
help="Describe the schedule's purpose or usage."
|
950 |
-
)
|
951 |
|
952 |
-
# Template selection
|
953 |
-
template_options = list(DEFAULT_SCHEDULE_TEMPLATES.keys())
|
954 |
selected_template = st.selectbox(
|
955 |
"Select Template",
|
956 |
options=["None"] + template_options,
|
957 |
index=template_options.index(editor_state.get("template", "custom")) + 1
|
958 |
-
if editor_state.get("template") in template_options else 0
|
959 |
-
help="Select a template to prefill the schedule, or 'None' to start from scratch."
|
960 |
)
|
961 |
|
962 |
-
#
|
963 |
-
if
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
973 |
|
974 |
-
# CSS
|
975 |
st.markdown("""
|
976 |
<style>
|
977 |
.slider-container {
|
@@ -983,15 +995,12 @@ def display_schedules_tab():
|
|
983 |
padding: 10px;
|
984 |
overflow-x: auto;
|
985 |
min-width: 100%;
|
986 |
-
box-sizing: border-box;
|
987 |
}
|
988 |
.slider-item {
|
989 |
display: flex;
|
990 |
flex-direction: column;
|
991 |
align-items: center;
|
992 |
width: 45px;
|
993 |
-
min-width: 45px;
|
994 |
-
margin: 0 2px;
|
995 |
}
|
996 |
.hour-label {
|
997 |
text-align: center;
|
@@ -1003,68 +1012,51 @@ def display_schedules_tab():
|
|
1003 |
.stVerticalSlider {
|
1004 |
height: 150px !important;
|
1005 |
}
|
1006 |
-
.stVerticalSlider .slider-track {
|
1007 |
-
background: #e0e0e0 !important;
|
1008 |
-
}
|
1009 |
-
.stVerticalSlider .slider-thumb {
|
1010 |
-
background: #333 !important;
|
1011 |
-
border: 2px solid #fff !important;
|
1012 |
-
}
|
1013 |
</style>
|
1014 |
""", unsafe_allow_html=True)
|
1015 |
|
1016 |
-
# Reusable
|
1017 |
-
def
|
1018 |
-
sliders = []
|
1019 |
st.markdown('<div class="slider-container">', unsafe_allow_html=True)
|
|
|
1020 |
for hour in range(24):
|
1021 |
-
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
st.markdown('</div>', unsafe_allow_html=True)
|
1039 |
-
sliders.append(val if val is not None else float(values[hour]))
|
1040 |
st.markdown('</div>', unsafe_allow_html=True)
|
1041 |
-
return
|
1042 |
|
1043 |
-
#
|
1044 |
st.write("**Weekday Schedule**")
|
1045 |
-
weekday_schedule =
|
1046 |
|
1047 |
-
# Weekend schedule
|
1048 |
st.write("**Weekend Schedule**")
|
1049 |
-
weekend_schedule =
|
1050 |
|
1051 |
-
#
|
1052 |
-
st.write("**Saved Schedules**")
|
1053 |
schedules = st.session_state.project_data["internal_loads"]["schedules"]
|
1054 |
-
if schedules:
|
1055 |
-
display_schedules_table(schedules)
|
1056 |
-
else:
|
1057 |
-
st.write("No schedules available.")
|
1058 |
-
|
1059 |
-
# Action buttons
|
1060 |
col1, col2 = st.columns(2)
|
|
|
1061 |
with col1:
|
1062 |
-
|
1063 |
-
if st.button(submit_label):
|
1064 |
if not name.strip():
|
1065 |
st.error("Schedule name is required.")
|
1066 |
elif name in schedules and not is_edit:
|
1067 |
-
st.error("
|
1068 |
else:
|
1069 |
schedule_data = {
|
1070 |
"description": description,
|
@@ -1072,28 +1064,30 @@ def display_schedules_tab():
|
|
1072 |
"weekend": weekend_schedule
|
1073 |
}
|
1074 |
|
1075 |
-
|
1076 |
-
|
1077 |
-
original_name
|
1078 |
-
if original_name != name and original_name in schedules:
|
1079 |
del schedules[original_name]
|
1080 |
-
|
1081 |
-
st.success(f"Schedule '{name}' updated successfully!")
|
1082 |
-
else:
|
1083 |
-
schedules[name] = schedule_data
|
1084 |
-
st.success(f"Schedule '{name}' added successfully!")
|
1085 |
|
1086 |
-
# Reset
|
1087 |
st.session_state.schedule_editor = {}
|
1088 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
|
|
1089 |
st.rerun()
|
1090 |
|
1091 |
with col2:
|
1092 |
if st.button("Cancel"):
|
1093 |
st.session_state.schedule_editor = {}
|
1094 |
-
st.session_state.module_rerun_flags["internal_loads"] = True
|
1095 |
st.rerun()
|
1096 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1097 |
def is_schedule_in_use(schedule_name: str) -> bool:
|
1098 |
"""
|
1099 |
Check if a schedule is in use by any people, lighting, equipment, or ventilation/infiltration systems.
|
|
|
927 |
"""
|
928 |
Display the schedules tab content with vertical sliders for hourly schedules.
|
929 |
"""
|
930 |
+
import streamlit as st
|
931 |
+
from streamlit_vertical_slider import vertical_slider
|
932 |
+
|
933 |
st.subheader("Schedules Editor")
|
934 |
|
935 |
+
# Initialise schedule editor state
|
936 |
if "schedule_editor" not in st.session_state:
|
937 |
st.session_state.schedule_editor = {}
|
938 |
|
939 |
+
if "template_selected" not in st.session_state:
|
940 |
+
st.session_state.template_selected = False
|
941 |
+
|
942 |
editor_state = st.session_state.schedule_editor
|
943 |
is_edit = editor_state.get("is_edit", False)
|
944 |
|
945 |
+
# Load available templates
|
946 |
+
template_options = list(DEFAULT_SCHEDULE_TEMPLATES.keys())
|
|
|
|
|
|
|
|
|
947 |
|
948 |
+
# Text inputs
|
949 |
+
name = st.text_input("Schedule Name", value=editor_state.get("name", ""))
|
950 |
+
description = st.text_area("Description", value=editor_state.get("description", ""))
|
|
|
|
|
951 |
|
|
|
|
|
952 |
selected_template = st.selectbox(
|
953 |
"Select Template",
|
954 |
options=["None"] + template_options,
|
955 |
index=template_options.index(editor_state.get("template", "custom")) + 1
|
956 |
+
if editor_state.get("template") in template_options else 0
|
|
|
957 |
)
|
958 |
|
959 |
+
# Set flag and rerun if new template is selected
|
960 |
+
if selected_template != editor_state.get("template", "None"):
|
961 |
+
if selected_template != "None":
|
962 |
+
template_data = DEFAULT_SCHEDULE_TEMPLATES[selected_template]
|
963 |
+
st.session_state.schedule_editor = {
|
964 |
+
"template": selected_template,
|
965 |
+
"weekday": template_data["weekday"],
|
966 |
+
"weekend": template_data["weekend"],
|
967 |
+
"name": name,
|
968 |
+
"description": description,
|
969 |
+
"is_edit": is_edit,
|
970 |
+
}
|
971 |
+
else:
|
972 |
+
st.session_state.schedule_editor = {
|
973 |
+
"template": "None",
|
974 |
+
"weekday": [0.0] * 24,
|
975 |
+
"weekend": [0.0] * 24,
|
976 |
+
"name": name,
|
977 |
+
"description": description,
|
978 |
+
"is_edit": is_edit,
|
979 |
+
}
|
980 |
+
st.rerun()
|
981 |
+
|
982 |
+
# Get values from editor state
|
983 |
+
weekday_values = editor_state.get("weekday", [0.0] * 24)
|
984 |
+
weekend_values = editor_state.get("weekend", [0.0] * 24)
|
985 |
|
986 |
+
# CSS styling
|
987 |
st.markdown("""
|
988 |
<style>
|
989 |
.slider-container {
|
|
|
995 |
padding: 10px;
|
996 |
overflow-x: auto;
|
997 |
min-width: 100%;
|
|
|
998 |
}
|
999 |
.slider-item {
|
1000 |
display: flex;
|
1001 |
flex-direction: column;
|
1002 |
align-items: center;
|
1003 |
width: 45px;
|
|
|
|
|
1004 |
}
|
1005 |
.hour-label {
|
1006 |
text-align: center;
|
|
|
1012 |
.stVerticalSlider {
|
1013 |
height: 150px !important;
|
1014 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1015 |
</style>
|
1016 |
""", unsafe_allow_html=True)
|
1017 |
|
1018 |
+
# Reusable vertical slider row
|
1019 |
+
def render_sliders(prefix, values, colour):
|
|
|
1020 |
st.markdown('<div class="slider-container">', unsafe_allow_html=True)
|
1021 |
+
results = []
|
1022 |
for hour in range(24):
|
1023 |
+
st.markdown('<div class="slider-item">', unsafe_allow_html=True)
|
1024 |
+
val = vertical_slider(
|
1025 |
+
label="",
|
1026 |
+
key=f"{prefix}_{hour}",
|
1027 |
+
height=150,
|
1028 |
+
step=0.01,
|
1029 |
+
min_value=0.0,
|
1030 |
+
max_value=1.0,
|
1031 |
+
default_value=values[hour],
|
1032 |
+
slider_color=colour,
|
1033 |
+
track_color="#e0e0e0",
|
1034 |
+
thumb_color="#333",
|
1035 |
+
value_always_visible=False
|
1036 |
+
)
|
1037 |
+
st.markdown(f'<div class="hour-label">{hour:02d}:00</div>', unsafe_allow_html=True)
|
1038 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
1039 |
+
results.append(val)
|
|
|
|
|
1040 |
st.markdown('</div>', unsafe_allow_html=True)
|
1041 |
+
return results
|
1042 |
|
1043 |
+
# Render sliders
|
1044 |
st.write("**Weekday Schedule**")
|
1045 |
+
weekday_schedule = render_sliders("weekday", weekday_values, "#4CAF50")
|
1046 |
|
|
|
1047 |
st.write("**Weekend Schedule**")
|
1048 |
+
weekend_schedule = render_sliders("weekend", weekend_values, "#2196F3")
|
1049 |
|
1050 |
+
# Save or update
|
|
|
1051 |
schedules = st.session_state.project_data["internal_loads"]["schedules"]
|
|
|
|
|
|
|
|
|
|
|
|
|
1052 |
col1, col2 = st.columns(2)
|
1053 |
+
|
1054 |
with col1:
|
1055 |
+
if st.button("Save" if is_edit else "Add"):
|
|
|
1056 |
if not name.strip():
|
1057 |
st.error("Schedule name is required.")
|
1058 |
elif name in schedules and not is_edit:
|
1059 |
+
st.error("Schedule already exists.")
|
1060 |
else:
|
1061 |
schedule_data = {
|
1062 |
"description": description,
|
|
|
1064 |
"weekend": weekend_schedule
|
1065 |
}
|
1066 |
|
1067 |
+
if is_edit:
|
1068 |
+
original_name = editor_state.get("original_name", name)
|
1069 |
+
if original_name in schedules:
|
|
|
1070 |
del schedules[original_name]
|
1071 |
+
schedules[name] = schedule_data
|
|
|
|
|
|
|
|
|
1072 |
|
1073 |
+
# Reset state
|
1074 |
st.session_state.schedule_editor = {}
|
1075 |
st.session_state.module_rerun_flags["internal_loads"] = True
|
1076 |
+
st.success(f"Schedule '{name}' saved.")
|
1077 |
st.rerun()
|
1078 |
|
1079 |
with col2:
|
1080 |
if st.button("Cancel"):
|
1081 |
st.session_state.schedule_editor = {}
|
|
|
1082 |
st.rerun()
|
1083 |
|
1084 |
+
# Show saved schedules (optional)
|
1085 |
+
st.write("**Saved Schedules**")
|
1086 |
+
if schedules:
|
1087 |
+
display_schedules_table(schedules)
|
1088 |
+
else:
|
1089 |
+
st.info("No schedules saved yet.")
|
1090 |
+
|
1091 |
def is_schedule_in_use(schedule_name: str) -> bool:
|
1092 |
"""
|
1093 |
Check if a schedule is in use by any people, lighting, equipment, or ventilation/infiltration systems.
|