-
Notifications
You must be signed in to change notification settings - Fork 0
/
data_tools.py
188 lines (145 loc) · 6.58 KB
/
data_tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
from building_data_requests import get_value, get_bulk
from main import HeatmapMain
import pandas as pd
import numbers
import requests
from tempfile import mkstemp
from shutil import move
from os import fdopen, remove
current_air_data = None
rooms_and_sensors = None
def init_data_tools(rooms_and_sensors_path):
global rooms_and_sensors
# Read spreadsheet into a DataFrame.
# Each row contains the following:
# - Label
# - Facility
# - Instance ID of CO2 sensor
# - Instance ID of temperature sensor
rooms_and_sensors = pd.read_csv(rooms_and_sensors_path, na_filter=False, comment='#')
update_air_data()
def update_air_data():
global current_air_data
current_air_data = get_bulk_request_df()
current_air_data['temperature'] = pd.to_numeric(current_air_data['temperature'], errors='coerce')
current_air_data['co2'] = pd.to_numeric(current_air_data['co2'], errors='coerce')
def get_request_df(room):
row = rooms_and_sensors[rooms_and_sensors['Label'] == str(room)]
if not row.empty:
try:
temp_value, temp_units = get_value(row['Facility'].iloc[0], row['Temperature'].iloc[0], True)
co2_value, co2_units = get_value(row['Facility'].iloc[0], row['CO2'].iloc[0], True)
except requests.exceptions.ConnectionError:
raise ConnectionError("Unable to get data. Are you connected to the right WiFi network?")
# Prepare to print
temp_value = int(temp_value) if temp_value else ''
temp_units = temp_units if temp_units else ''
co2_value = int(co2_value) if co2_value else ''
co2_units = co2_units if co2_units else ''
df_dictionary = {
'room': [room if temp_value and temp_units else ''],
# If there's no data, leave the dictionary empty so the failsafe below catches it
'temperature': [temp_value],
'temperature units': [temp_units],
'co2': [co2_value],
'co2 units': [co2_units]
}
if not df_dictionary:
return None
return pd.DataFrame.from_dict(df_dictionary)
else:
return None
def get_bulk_request_df():
bulk_rq = []
# Iterate over the rows of the dataframe, adding elements to the bulk request
for index, row in rooms_and_sensors.iterrows():
# Append facility/instance pairs to bulk request
if row['Temperature']:
bulk_rq.append({'facility': row['Facility'], 'instance': row['Temperature']})
if row['CO2']:
bulk_rq.append({'facility': row['Facility'], 'instance': row['CO2']})
# Issue get-bulk request
try:
bulk_rsp = get_bulk(bulk_rq)
except requests.exceptions.ConnectionError:
raise ConnectionError("Unable to get data from. Are you connected to the right WiFi network?")
# Extract map from get-bulk response
map = bulk_rsp['rsp_map']
df_dictionary = {
'room': [],
'temperature': [],
'temperature units': [],
'co2': [],
'co2 units': []
}
# Iterate over the rows of the DataFrame, displaying temperature and CO2 values extracted from map
for index, row in rooms_and_sensors.iterrows():
# Initialize empty display values
temp_value = ''
temp_units = ''
co2_value = ''
co2_units = ''
# Get facility of current row
facility = row['Facility']
# Try to extract current row's temperature and CO2 values from map
if facility in map:
instance = str(row['Temperature'])
if instance and (instance in map[facility]):
rsp = map[facility][instance]
property = rsp['property']
temp_value = int(rsp[property]) if isinstance(rsp[property], numbers.Number) else ''
temp_units = rsp['units']
instance = str(row['CO2'])
if instance and (instance in map[facility]):
rsp = map[facility][instance]
property = rsp['property']
co2_value = int(rsp[property]) if isinstance(rsp[property], numbers.Number) else ''
co2_units = rsp['units']
# Output CSV format
df_dictionary['room'].append(row['Label'])
df_dictionary['temperature'].append(temp_value)
df_dictionary['temperature units'].append(temp_units)
df_dictionary['co2'].append(co2_value)
df_dictionary['co2 units'].append(co2_units)
return pd.DataFrame.from_dict(df_dictionary)
def get_room_data(room):
return current_air_data[current_air_data['room'] == room] if current_air_data is not None else None
def get_room_row_index(room):
for indx, row in current_air_data.iterrows():
if row['room'] == room or row['room'] == str(room):
return indx
return None
def get_new_room_data(room):
global current_air_data
# Pull some new data from the BACnet, and replace the old data in current_air_data with it
room_data = get_request_df(room)
if room_data is not None:
current_data_room_index = get_room_row_index(room)
if current_data_room_index is not None:
current_air_data.at[current_data_room_index, 'temperature'] = room_data['temperature'].iloc[0]
current_air_data.at[current_data_room_index, 'temperature units'] = room_data['temperature units'].iloc[0]
current_air_data.at[current_data_room_index, 'co2'] = room_data['co2'].iloc[0]
current_air_data.at[current_data_room_index, 'co2 units'] = room_data['co2 units'].iloc[0]
return room_data
else:
return None
def fill_all_rooms(heatmap, is_temperature_value):
if not isinstance(heatmap, HeatmapMain):
return # We will get run time errors later on if heatmap is not an instance of HeatmapMain
for indx, row in current_air_data.iterrows():
heatmap.fill_from_data(row, is_temperature_value)
heatmap.add_overlay(is_temperature_value)
replace_in_file(
'{0}_filled_rooms_{1}.svg'.format(heatmap.svg_path[:-4], 'temperature' if is_temperature_value else 'co2'), 'svg:', '') # Cleanup broken formatting that svgwrite sometimes generates
# Code from https://stackoverflow.com/questions/39086/search-and-replace-a-line-in-a-file-in-python
def replace_in_file(file_path, pattern, replacement):
# Create temp file
fh, abs_path = mkstemp()
with fdopen(fh, 'w') as new_file:
with open(file_path) as old_file:
for line in old_file:
new_file.write(line.replace(pattern, replacement))
# Remove original file
remove(file_path)
# Move new file
move(abs_path, file_path)