The package can be installed through use of pip:
pip install --upgrade bmondata
The --upgrade
flag ensures that the newest version will replace a bmondata version
that you may already have.
The Server class is used to initiate requests to one BMON Server. The base URL of the BMON server is the one required parameter when instatiating the object. If you want to use the Server object to store sensor readings on the server, you also need to provide the 'store_key' parameter. The 'store_key' is the secret key found in the settings.py file on the BMON server.
import bmondata
# Make a Server object for retrieving data only
server = bmondata.Server('https://bmon.analysisnorth.com')
# The Server object below can also be used to store sensor readings
# on the BMON server.
server = bmondata.Server('https://bmon.analysisnorth.com', store_key='temporary-key')
The sensor_readings()
method is used to retrieve sensor readings from one or
more sensors. The readings are returned in a Pandas DataFrame. To retrieve
readings from one sensor, specify the Sensor ID as the first parameter. (You can
determine a Sensor ID by viewing the 'Current Sensor Values' report and then hovering your
cursor over the name of a sensor; the Sensor ID will be shown on the last line of
the pop-up window.)
df = server.sensor_readings('phil_hp_pwr_10187_temp')
df.head()
The timezone used for the date/time stamps defaults to the timezone of the building that the sensor
is associated with. If there are multiple buildings linked to the sensor, the most prevalent timezone
is used. However, you can force the timestamps to use a particular timezone by adding a timezone
parameter to the function call:
df = server.sensor_readings('phil_hp_pwr_10187_temp', timezone='US/Alaska')
The timezone parameter is a string value and must be one of the values in the list pytz.all_timezones (pytz is a pip-installable Python package).
To retrieve readings from multiple sensors, provide a list of Sensor IDs:
df = df = server.sensor_readings(['phil_hp_pwr_10187_temp', 'phil_hp_pwr_7470_temp'])
df.head()
Readings from multiple sensors often are not synchronized in time, thus the DataFrame will include many NaN values. Time-averaging of readings is discussed later and can eliminate most of the NaN values.
You can have the DataFrame use more meaningful column names by providing a column label for one or more of the sensors:
sensors = [
('phil_hp_pwr_10187_temp', 'outdoor_temp'),
'phil_hp_pwr_7470_temp'
]
df = server.sensor_readings(sensors)
df.head()
For each Sensor that you wish to label, use a two-tuple containing the Sensor ID and the Sensor Label instead of just supplying the Sensor ID.
To filter the readings based on date/time, use the start_ts
and end_ts
parameters:
df = server.sensor_readings(
sensors,
start_ts = '2019-01-15 3:00 pm',
end_ts = '2019-01-17 10:30 am'
)
df.head()
The format of start_ts
and end_ts
is very flexible. Any date/time that can be
parsed by dateutil.parser.parse() will work. If start_ts
is not provided, readings
start at the earliest available; if end_ts
is not provided, readings continue through
the latest available.
You can request that the sensor readings be averaged into time periods such as 1 hour or 1 day. For a full list of the possible time period codes, see DateOffset Objects. Here is an example for 1 hour averaging:
df = server.sensor_readings(
sensors,
start_ts = '2019-01-15 3:00 pm',
end_ts = '2019-01-17 10:30 am',
averaging = '1H'
)
df.head()
The default is to label the time period with the time at left (beginning) edge of the
interval. If instead you want the timestamp to fall at a different point in the
interval, you can use the label_offset
parameter to shift it. Here we mark the
middle of the interval by using an offset of 30 minutes:
df = server.sensor_readings(
sensors,
start_ts = '2019-01-15 3:00 pm',
end_ts = '2019-01-17 10:30 am',
averaging = '1H',
label_offset = '30min'
)
df.head()
Sensor titles, units and other information can be retrieved for one or more
sensors by using the sensors()
method. Pass a Sensor ID or a list of Sensor
IDs to the method:
server.sensors(['phil_hp_pwr_10187_temp', 'phil_hp_pwr_7470_temp'])
The return value is a list of dictionaries, each dictionary describing a Sensor.
The keys in the dictionary are the fields associated with the Sensor model in the
BMON Django application. The buildings
key in the dictionary gives a list of
buildings that the Sensor is associated with.
Further documentation of the fields is available
Here; search
for the class Sensor
section of the code.
If you do not provide any IDs (either no parameters, or an empty list), information
for all sensors will be returned. For example, server.sensors()
will return
a list of all sensors.
Methods are available to return information about Buildings and Organizations in the BMON system. Pass one or a list of Building IDs to get Building information:
server.buildings([6, 13])
The sensors
item gives a list of Sensors associated with the Building. The
organizations
item shows the organizations that the building is associated with.
The fuel_rate
and electric_rate
items give the fuel and electric rate schedules, if present.
Seach class FuelRate
and class ElectricRate
Here
to see documentation of the rate structure fields.
Further documentation of the other fields is available
Here; search
for the class Building
section of the code.
If you do not provide any IDs (either no parameters, or an empty list), information for all buildings will be returned.
Here is the method for retrieving information about Organizations:
server.organizations([1, 2])
The buildings
key gives the list of buildings associated with the organization.
Again, further documentation of the fields is available
Here; search
for the class Organization
section of the code. server.organizations()
will return
information on all Organizations.
The bmondata
package can be used to store new sensor readings into
the BMON server's sensor reading database. Readings are stored using the Server
object, and a list of new readings are provided. Here is an example:
import time
server.store_sensor_readings([
(time.time(), '_testing', 18.8),
(time.time(), '_hello', 24.3),
])
The value returned is the number of readings that were successfully stored.
A couple of utility functions are available to help process the data in some of the
fields returned to describe Buildings. Currently, there are two functions: bmondata.csnl_to_list
and bmondata.split_strip
. Both functions split and clean a string and will be useful for
turning a field containing Sensor IDs into a Python list. Here is the code for the
two functions:
def csnl_to_list(csnl_str):
"""Converts a comma-separated and new-line separated string into
a list, stripping whitespace from both ends of each item. Does not
return any zero-length strings.
"""
s = csnl_str.replace('\n', ',')
return [it.strip() for it in s.split(',') if it.strip()]
def split_strip(s, delim=','):
"""Converts a delimited string into a list, stripping whitespace
from both ends of each item. Does not return any zero-length strings.
'delim' is the delimiter.
"""
return [it.strip() for it in s.split(',') if it.strip()]
!jupyter nbconvert usage_examples.ipynb --to html
import boto3
s3 = boto3.resource('s3')
s3.meta.client.upload_file(
'usage_examples.html',
'web.analysisnorth.com',
'bmondata/usage_examples.html',
ExtraArgs={'ContentType': 'text/html'}
)