Venue 86 - Thermopro loggers, 2025

Venue 86 - Thermopro loggers, 2025#

Venue 86 was able to deploy a bunch of Thermpro TP357s at once. We’re plotting separately from last time as it’s been a while. We’re using the same labels as before but we haven’t received confirmation that the same Thermopros are in the same locations.

The green stripes are when the venue was occupied. The black squares are their records of the heating timings - from memory, so they may be imperfect, but it’s brilliant to have these.

You can get a line to disappear by clicking on it in the legend, sweep out part of the plot to zoom in, and so on.

Hide code cell source

# Using plotly.express

plot_height = 800
plot_width = 1000

venue_data_dir = "./venue-86/"
venue_temp_data_dir = venue_data_dir + "tranche2/" 
weather_data_dir = "./weather_data/"


temp_filenames = ['ThermoProSensor_export_TP357S(1)_03112025.csv' , 'ThermoProSensor_export_TP357S(3)_03112025.csv' , 'ThermoProSensor_export_TP357S(6)_03112025.csv', 'ThermoProSensor_export_TP357S(2)_03112025.csv' , 'ThermoProSensor_export_TP357S(4)_03112025.csv',  'ThermoProSensor_export_TP357S(7)_03112025.csv']
location_labels= ["1 - lady_chapel","2 - north_aisle_rear","3 - right_back_pew", "4 - nave_aisle_central","5 - nave_aisle_near_front", "6 - choir", "7 - organ_loft"]

# For their own set of Thermopros starting Dec 2024, they changed the numbering - for now just being careful what file I append to.
# Sensor 1: Lady Chapel
# Sensor 2: Back of church
# Sensor 3: Middle of church
# Sensor 4: Front of church
# Sensor 5: Choir stalls
# Sensor 6: Organ loft
# Sensor 7: Sacristy - only installed in last couple of weeks

weather_location_labels = ["3 - right_back_pew", "7 - organ_loft"] # used to plot against weather data.
use_diary_filepath = venue_data_dir + "use_diary.csv"
heating_timings_filepath =  venue_data_dir + "heating_timings.csv"
weather_filepath = weather_data_dir + "gcht2024_weather_data.csv"



# import ipywidgets as widgets
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go   
import os as os
from datetime import datetime as dt

list_of_temp_traces = []
list_of_rh_traces = []
list_of_traces_for_weather_comparison = []
dfHeatTimes = pd.DataFrame()
dfUseDiary = pd.DataFrame()

if os.path.isfile(use_diary_filepath):
    dfUseDiary = pd.read_csv(use_diary_filepath)
    dfUseDiary = dfUseDiary.fillna('')
    dfUseDiary['annotation_position'] = dfUseDiary['annotation_position'].replace(to_replace="", value="top left")
    dfUseDiary['start'] = pd.to_datetime(dfUseDiary['startUse'])
    dfUseDiary['end'] = pd.to_datetime(dfUseDiary['endUse'])
    #print(dfUseDiary)

if os.path.isfile(heating_timings_filepath):
    dfHeatTimes = pd.read_csv(heating_timings_filepath)
    dfHeatTimes = dfHeatTimes.fillna('')
    dfHeatTimes['start'] = pd.to_datetime(dfHeatTimes['startHeat'])
    dfHeatTimes['end'] = pd.to_datetime(dfHeatTimes['endHeat'])

# find some useful limits for rendering the weather data
  
end = dt.strptime("1970-01-01 00:00", '%Y-%m-%d %H:%M')
start = dt.strptime("2030-01-01 00:00", '%Y-%m-%d %H:%M')

for temp_filename,location_label in zip(temp_filenames,location_labels):
    df = pd.read_csv(venue_temp_data_dir + temp_filename,encoding='latin-1',usecols=[0,1,2], header=1, names=[ 'time','temperature','rh'])
    df["timestamp"] = pd.to_datetime(df['time'], dayfirst=True)
    df = df.fillna('')
    start_time_in_file = df['timestamp'].min() # TODO earliest overall, compare and replace, make range limit for weather data
    end_time_in_file = df['timestamp'].max()
    if start_time_in_file < start:
            start = start_time_in_file
    if end_time_in_file > end:
            end = end_time_in_file
    
    #range_min = df['timestamp'].min()
    #range_max = df['timestamp'].max()
    #print(range_min, " to ", range_max) # this just uses the range of the last file, not ideal
    
    
    trace = go.Scatter(customdata=df, 
                        y=df['temperature'], 
                        x = df['timestamp'], 
                        mode='lines', 
                        hoverinfo='all', 
                        name=location_label,
                        )
    list_of_temp_traces.append(trace)

    # take a few traces and add to plot it against the weather.
    if (location_label in weather_location_labels):
        list_of_traces_for_weather_comparison.append(trace)
    
    trace = go.Scatter(customdata=df, 
                        y=df['rh'], 
                        x = df['timestamp'], 
                        mode='lines', 
                        hoverinfo='all', 
                        name=location_label,
                        )
    list_of_rh_traces.append(trace)

# create a trace for the weather data

df = pd.read_csv(weather_filepath,encoding='latin-1',usecols=[0,1], header=1, names=[ 'time','temperature'])
df["timestamp"] = pd.to_datetime(df['time'])
df = df.fillna('')
df = df[(df['timestamp'] > start) & (df['timestamp'] < end)] 
print("weather min is: ",df['timestamp'].min())
print("weather max is: ",df['timestamp'].max())
    
trace = go.Scatter(customdata=df, 
                        y=df['temperature'], 
                        x = df['timestamp'], 
                        mode='lines', 
                        hoverinfo='all', 
                        name="outside",
                        )

list_of_traces_for_weather_comparison.append(trace)



temp_g = go.FigureWidget(data=list_of_temp_traces,
                    layout = go.Layout(
                        yaxis=dict(range=[9,28])
                    ))



rh_g = go.FigureWidget(data=list_of_rh_traces,
                    layout = go.Layout(
                        yaxis=dict(range=[0,100])
                    ))


weather_g = go.FigureWidget(data=list_of_traces_for_weather_comparison,
                    layout = go.Layout(
                        yaxis=dict(range=[-6,25])
                    ))



temp_fig = go.Figure(temp_g)
temp_fig.update_layout(showlegend=True, 
              autosize = True, 
              title= "Temperature (deg C))",
              width=plot_width, 
              height=plot_height,
)

# example syntax for two plots on same x-axis - I'd like to show the boiler temperature in
# parallel - but havne't had time to sort the syntax.
#temp_fig = make_subplots(rows=2, cols=1, shared_xaxes=True)

# for i, col in enumerate(cols, start=1):
#     fig.add_trace(go.Scatter(x=df[col].index, y=df[col].values), row=i, col=1)

rh_fig = go.Figure(rh_g)
rh_fig.update_layout(showlegend=True, 
              autosize = True, 
              title= "Relative Humidity (%RH)",
              width=plot_width, 
              height=plot_height,
)

weather_fig = go.Figure(weather_g)
weather_fig.update_layout(showlegend=True, 
              autosize = True, 
              title= "Indoor vs outdoor temperature from weather station (deg C))",
              width=plot_width, 
              height=plot_height,
)

temp_fig.update_layout(
    hovermode='x unified',
   # range=[range_min, range_max],
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

#Add range slider
temp_fig.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)

for ind in dfUseDiary.index:
    temp_fig.add_vrect(x0=dfUseDiary['start'][ind], x1=dfUseDiary['end'][ind],
                annotation_text=dfUseDiary['label'][ind], 
                annotation_position=dfUseDiary['annotation_position'][ind],
                annotation=dict(font_size=14, 
                font_family="Times New Roman"),
                fillcolor="green", 
                opacity=0.25, 
                line_width=0)
        

for ind in dfHeatTimes.index:
    temp_fig.add_vrect(x0=dfHeatTimes['start'][ind], x1=dfHeatTimes['end'][ind])
 
#fig.add_hline(y=16, annotation_text='16C - usual minimum for children', annotation_font_color="blue", line_color='red', layer='above', line_dash='dash')
# fig.update_yaxes(range = [-5, dfCollatedDataSet['temperature'].max()+5])
temp_fig.show()

rh_fig.update_layout(
    hovermode='x unified',
   # range=[range_min, range_max],
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

#Add range slider
rh_fig.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)


#fig.add_hline(y=16, annotation_text='16C - usual minimum for children', annotation_font_color="blue", line_color='red', layer='above', line_dash='dash')
# fig.update_yaxes(range = [-5, dfCollatedDataSet['temperature'].max()+5])
rh_fig.show()

weather_fig.update_layout(
    hovermode='x unified',
   # range=[range_min, range_max],
    hoverlabel=dict(
        bgcolor="white",
        # font_size=16,
        font_family="Rockwell"
    )
)

#Add range slider
weather_fig.update_layout(
    xaxis=dict(
        rangeselector=dict(
            buttons=list([
                dict(
                     label="All",
                     step="all"
                     ),
                                dict(count=1,
                     label="Hour",
                     step="hour",
                     stepmode="todate"),
                dict(count=1,
                     label="Day",
                     step="day",
                     stepmode="backward"),
                dict(count=7,
                     label="Week",
                     step="day",
                     stepmode="backward"),
                dict(count=1,
                     label="Year",
                     step="year",
                     stepmode="backward")
            ])
        ),
        rangeslider=dict(
            visible=True,
        ),
        type="date"
    )
)


for ind in dfHeatTimes.index:
    weather_fig.add_vrect(x0=dfHeatTimes['start'][ind], x1=dfHeatTimes['end'][ind])

#fig.add_hline(y=16, annotation_text='16C - usual minimum for children', annotation_font_color="blue", line_color='red', layer='above', line_dash='dash')
# fig.update_yaxes(range = [-5, dfCollatedDataSet['temperature'].max()+5])
weather_fig.show()
weather min is:  2024-12-15 13:00:00
weather max is:  2025-03-14 23:00:00