Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get and create meters and meter readings #18

Merged
merged 4 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.7, 3.9]
python-version: [3.9, 3.10.9]
test_env: [python, precommit, mypy]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Display system info
Expand All @@ -36,11 +36,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Install Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: "3.7"
python-version: "3.9"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repos:
- id: mixed-line-ending
args: ["--fix=auto"]
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v2.0.0
rev: v2.0.1
hooks:
- id: autopep8
args:
Expand All @@ -35,12 +35,12 @@ repos:
"--ignore=E501,E402,W503,W504,E731",
]
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
rev: 6.0.0
hooks:
- id: flake8
args: ["--ignore=E501,E402,W503,W504,E731,F401"]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
rev: v3.0.0-alpha.4
hooks:
- id: prettier
types_or: [css, yaml, markdown, html, scss, javascript]
Expand Down
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ This provides two user authentication based Python clients and two OAuth2 authen
SEED (Standard Energy Efficiency Data Platform™) is an open source "web-based application that helps organizations easily manage data on the energy performance of large groups of buildings" funded by the United States Department of Energy.

More information can be found here:

* https://energy.gov/eere/buildings/standard-energy-efficiency-data-platform
* http://seedinfo.lbl.gov/
* https://seed-platform.org
* https://github.com/SEED-platform
* https://buildingdata.energy.gov/#/seed


Note the clients do not provide per api-call methods, but does provide the standard CRUD methods: get, list, put, post, patch, delete
Expand Down
86 changes: 85 additions & 1 deletion pyseed/seed_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"""

# Imports from Standard Library
from typing import Any, Dict, List, Optional, Set, Tuple
from typing import Any, Dict, List, Optional, Set, Tuple, Union

# Imports from Third Party Modules
import json
Expand Down Expand Up @@ -947,6 +947,87 @@ def get_meters(self, property_id: int) -> list:
url_args={"PK": property_id})
return meters

def get_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Union[dict, None]:
"""get a meter for a property view.

Args:
property_view_id (int): property view id
meter_type (str): Type of meter, based off the enums in the SEED Meter model
source (str): Of GreenButton, Portfolio Manager, or Custom Meter
source_id (str): Identifier, if GreenButton, then format is xpath like

Returns:
dict: meter object
"""
# return all the meters for the property and see if the meter exists, if so, return it
meters = self.get_meters(property_view_id)
for meter in meters:
if meter['type'] == meter_type and meter['source'] == source and meter['source_id'] == source_id:
return meter
else:
return None

def get_or_create_meter(self, property_view_id: int, meter_type: str, source: str, source_id: str) -> Optional[Dict[Any, Any]]:
"""get or create a meter for a property view.

Args:
property_view_id (int): property view id
meter_type (str): Type of meter, based off the enums in the SEED Meter model
source (str): Of GreenButton, Portfolio Manager, or Custom Meter
source_id (str): Identifier, if GreenButton, then format is xpath like

Returns:
dict: meter object
"""
# return all the meters for the property and see if the meter exists, if so, return it
meter = self.get_meter(property_view_id, meter_type, source, source_id)
if meter:
return meter
else:
# create the meter
payload = {
'type': meter_type,
'source': source,
'source_id': source_id,
}

meter = self.client.post(
endpoint='properties_meters', url_args={"PK": property_view_id}, json=payload
)

return meter

def delete_meter(self, property_view_id: int, meter_id: int) -> dict:
"""Delete a meter from the property.

Args:
property_view_id (int): property view id
meter_id (int): meter id

Returns:
dict: status of the delete
"""
return self.client.delete(
meter_id, endpoint='properties_meters', url_args={"PK": property_view_id}
)

def upsert_meter_readings_bulk(self, property_view_id: int, meter_id: int, data: list) -> dict:
"""Upsert meter readings for a property's meter with the bulk method.

Args:
property_id (int): property id
meter_id (int): meter id
data (list): list of dictioanries of meter readings

Returns:
dict: list of all meter reading objects
"""
# get the meter data for the property
readings = self.client.post(
endpoint='properties_meters_reading', url_args={"PK": property_view_id, "METER_PK": meter_id}, json=data
)
return readings

def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_ids: list = []):
"""Return the meter data from the property.

Expand All @@ -962,6 +1043,9 @@ def get_meter_data(self, property_id, interval: str = 'Exact', excluded_meter_id
meter_data = self.client.post(endpoint='properties_meter_usage', url_args={"PK": property_id}, json=payload)
return meter_data

def save_meter_data(self, property_id: int, meter_id: int, meter_data) -> dict:
pass

def start_save_data(self, import_file_id: int) -> dict:
"""start the background process to save the data file to the database.
This is the state before the mapping.
Expand Down
13 changes: 9 additions & 4 deletions pyseed/seed_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@
'import_files_start_matching_pk': '/api/v3/import_files/PK/start_system_matching_and_geocoding/',
'import_files_check_meters_tab_exists_pk': '/api/v3/import_files/PK/check_meters_tab_exists/',
'org_column_mapping_import_file': 'api/v3/organizations/ORG_ID/column_mappings/',
'properties_meters_reading': '/api/v3/properties/PK/meters/METER_PK/readings/',
# GETs with replaceable keys
'import_files_matching_results': '/api/v3/import_files/PK/matching_and_geocoding_results/',
'progress': '/api/v3/progress/PROGRESS_KEY/',
'properties_meters': '/api/v3/properties/PK/meters/',
'properties_meter_usage': '/api/v3/properties/PK/meter_usage/',
'properties_meters_reading': '/api/v3/properties/PK/meters/METER_PK/readings/',
},
'v2': {
'columns': '/api/v2/columns/',
Expand Down Expand Up @@ -121,7 +123,7 @@ def _replace_url_args(url, url_args):
"""Replace any custom string URL items with values in args"""
if url_args:
for key, value in url_args.items():
url = url.replace(f"{key}/", f"{value}/")
url = url.replace(f"/{key}/", f"/{value}/")
return url


Expand Down Expand Up @@ -250,9 +252,12 @@ def _check_response(self, response, *args, **kwargs):
if error:
if response.content:
try:
error_msg = response.json().get(
'message', f"Unknown SEED Error {response.status_code}: {response.json()}"
)
if getattr(response.json(), "get", None):
error_msg = response.json().get(
'message', f"Unknown SEED Error {response.status_code}: {response.json()}"
)
else:
error_msg = f"Unknown SEED Error {response.status_code}: {response.json()}"
except ValueError:
error_msg = 'Unknown SEED Error: No response returned'
if args:
Expand Down