Venue 87 - Thermopro loggers

Venue 87 - Thermopro loggers#

Venue 87 was able to deploy a bunch of Thermopro 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
import os as os
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go  
from datetime import datetime as dt

plot_height = 800
plot_width = 1000

venue_data_dir = "./venue-87/"
venue_temp_data_dir1 = "first_tranche"
venue_temp_data_dir2 = "second_tranche" 
weather_data_dir = "./weather_data/"


temp_filenames = ['1.csv', '2.csv' ,'3.csv', '4.csv' ,'5.csv',  '6.csv', '7.csv' ,'8.csv',  '9.csv']
#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".

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

# 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): 
    df1 = pd.read_csv(os.path.join(venue_data_dir,venue_temp_data_dir1,temp_filename),encoding='latin-1',usecols=[0,1,2], header=1, names=[ 'time','temperature','rh'])
    df2 = pd.read_csv(os.path.join(venue_data_dir,venue_temp_data_dir2,temp_filename),encoding='latin-1',usecols=[0,1,2], header=1, names=[ 'time','temperature','rh'])
    #df = pd.read_csv(os.path.join(venue_data_dir,venue_temp_data_dir,temp_filename),encoding='latin-1',usecols=[1,2,3], header=1, names=[ 'temperature','rh', 'time'])
    df = pd.concat([df1,df2],ignore_index=True)
    df["timestamp"] = pd.to_datetime(df['time'], dayfirst=True)
    df = df.fillna('')
    start_time_in_file = df['timestamp'].min() 
    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)

    # 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('')
# removing unuseful weather data
df = df[(df['timestamp'] > start) & (df['timestamp'] < end)]

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