Venue 87 - Thermopro loggers#

Venue 87 was able to deploy a bunch of Thermpro TP357s at once.

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-87"
venue_temp_data_dir = venue_data_dir + "/" 
weather_data_dir = "./weather_data/"

temp_filenames = ['ThermoProSensor_export_1_09122024.csv' , 'ThermoProSensor_export_2_09122024.csv' ,'ThermoProSensor_export_3_09122024.csv',  \
                  'ThermoProSensor_export_4_09122024.csv' ,'ThermoProSensor_export_5_09122024.csv',  'ThermoProSensor_export_6_09122024.csv', \
                    'ThermoProSensor_export_7_09122024.csv','ThermoProSensor_export_8_09122024.csv','ThermoProSensor_export_9_09122024.csv']
location_labels= room_names=["1 - church_pillar_back_right", "2 - church_pillar_central", "3 - Lady_Chapel_organ_top", "4 - bishops_chair", "5 - choir_vestry_top_cupboard", "6 - hall_ft_cupboard", "7 - hall_top_of_md_cupboard", "8 - creche_noticeboard", "9 - church_office_top_shelf"]
weather_location_labels = ["2 - church_pillar_central","9 - church_office_top_shelf", "7 - hall_top_of_md_cupboard"] # 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"

# had to correct the times - Thermopro default export appears to have exactly the same format for am as pm so can only get from context. Did that in Excel by copying the first
# timestamp to column 4 as it was morning start, and then adding 1/24/4 to it for 15 minute intervals, filling down. 
# :TODO: if this is a common problem, need to specify the start timestamp in a constant here and add programmatically - but with some kind of check Thermopro never "skipped".

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

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

#from IPython.display import display

# now the homebuilt monitor 


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'])

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'])



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=[1,2,3], header=1, names=[ 'temperature','rh', 'time'])
    df["timestamp"] = pd.to_datetime(df['time'], dayfirst=True)
    df = df.fillna('')
    
    #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)

    # aim for representative one per space where there are questions about the relation to weather, just to make it easier to work with the plot.

    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('')

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,25])
                    ))

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])
                    ))


# 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.
#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)

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

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])

# just for this one, because no heating diary, add the use diary to the weather figure.
for ind in dfUseDiary.index:
    weather_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)

#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()