diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..848c9ed --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.8 + +WORKDIR /pv_live + +COPY requirements.txt /pv_live/requirements.txt + +RUN apt-get -qq update && apt-get -qq install -y \ + curl \ + git \ + wget \ + libproj-dev \ + proj-data \ + proj-bin \ + libgeos-dev \ + libgdal-dev \ + python-gdal \ + gdal-bin \ + > /dev/null + +RUN pip install --no-cache-dir git+https://github.com/SheffieldSolar/PV_Live-API.git@0.8 > /dev/null + +#RUN pip install --no-cache-dir -r /pv_live/requirements.txt > /dev/null +#COPY . /pv_live/ + +CMD ["python", "/pv_live/pv_tracker.py", "-h"] diff --git a/README.md b/README.md index b85615e..75e0663 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ # PV_Live A Python implementation of the PV_Live web API. See https://www.solar.sheffield.ac.uk/pvlive/ -**Latest Version: 0.7** +**Latest Version: 0.8** -**New! Updated 2021-01-15 to use PV_Live API v3.** +**New! Updated 2021-07-19 to include a Command Line Interface and Docker Image.** ## About this repository @@ -64,6 +64,45 @@ pvl = PVLive() |Get the latest aggregated outturn for **GSP** ID **120** (INDQ1 or "Indian Queens")|`pvl.latest(entity_type="gsp", entity_id=120)`|`(120, '2021-01-20T14:00:00Z', 1, 3.05604)` |Get the nationally aggregated GB PV outturn for all of 2020 as a DataFrame|`pvl.between(start=datetime(2020, 1, 1, 0, 30, tzinfo=pytz.utc), end=datetime(2021, 1, 1, tzinfo=pytz.utc), dataframe=True)`|![Screenshot of output](/misc/code_example_output.png?raw=true)| +## Command Line Utilities + +### pv_live + +This utility can be used to download data to a CSV file: + +``` +>> pv_live -h +usage: pvlive.py [-h] [-s ""] [-e ""] [--entity_type ] [--entity_id ] [-q] + [-o ] + +This is a command line interface (CLI) for the PV_Live API module + +optional arguments: + -h, --help show this help message and exit + -s "", --start "" + Specify a UTC start date in 'yyyy-mm-dd HH:MM:SS' format (inclusive), default behaviour is to retrieve the latest + outturn. + -e "", --end "" + Specify a UTC end date in 'yyyy-mm-dd HH:MM:SS' format (inclusive), default behaviour is to retrieve the latest outturn. + --entity_type + Specify an entity type, either 'gsp' or 'pes'. Default is 'pes'. + --entity_id + Specify an entity ID, default is 0 (i.e. national). + -q, --quiet Specify to not print anything to stdout. + -o , --outfile + Specify a CSV file to write results to. + +Jamie Taylor, 2018-06-04 +``` + +## Using the Docker Image + +There is also a Docker Image hosted on Docker Hub which can be used to download data from the PV_Live API with minimal setup: + +``` +>> docker run -it --rm sheffieldsolar/pv_live-api: pv_live -h +``` + ## Documentation * [https://sheffieldsolar.github.io/PV_Live-API/](https://sheffieldsolar.github.io/PV_Live-API/) diff --git a/docs/source/conf.py b/docs/source/conf.py index c48086f..bc121f8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -59,9 +59,9 @@ # built documents. # # The short X.Y version. -version = u'0.7' +version = u'0.8' # The full version, including alpha/beta/rc tags. -release = u'0.7' +release = u'0.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pvlive_api/pvlive.py b/pvlive_api/pvlive.py index ea7e694..4be969b 100644 --- a/pvlive_api/pvlive.py +++ b/pvlive_api/pvlive.py @@ -16,6 +16,7 @@ import inspect import pytz import requests +import argparse from numpy import nan, int64 import pandas as pd @@ -370,10 +371,77 @@ def _validate_inputs(self, entity_type="pes", entity_id=0, extra_fields=""): if entity_id not in self.gsp_ids: raise PVLiveException(f"The gsp_id {entity_id} was not found.") +def parse_options(): + """Parse command line options.""" + parser = argparse.ArgumentParser(description=("This is a command line interface (CLI) for the " + "PV_Live API module"), + epilog="Jamie Taylor, 2018-06-04") + parser.add_argument("-s", "--start", metavar="\"\"", dest="start", + action="store", type=str, required=False, default=None, + help="Specify a UTC start date in 'yyyy-mm-dd HH:MM:SS' format " + "(inclusive), default behaviour is to retrieve the latest outturn.") + parser.add_argument("-e", "--end", metavar="\"\"", dest="end", + action="store", type=str, required=False, default=None, + help="Specify a UTC end date in 'yyyy-mm-dd HH:MM:SS' format (inclusive), " + "default behaviour is to retrieve the latest outturn.") + parser.add_argument("--entity_type", metavar="", dest="entity_type", + action="store", type=str, required=False, default="pes", + choices=["gsp", "pes"], + help="Specify an entity type, either 'gsp' or 'pes'. Default is 'pes'.") + parser.add_argument("--entity_id", metavar="", dest="entity_id", action="store", + type=int, required=False, default=0, + help="Specify an entity ID, default is 0 (i.e. national).") + parser.add_argument("-q", "--quiet", dest="quiet", action="store_true", + required=False, help="Specify to not print anything to stdout.") + parser.add_argument("-o", "--outfile", metavar="", dest="outfile", + action="store", type=str, required=False, + help="Specify a CSV file to write results to.") + options = parser.parse_args() + def handle_options(options): + """Validate command line args and pre-process where necessary.""" + if (options.outfile is not None and os.path.exists(options.outfile)) and not options.quiet: + try: + input(f"The output file '{options.outfile}' already exists and will be " + "overwritten, are you sure you want to continue? Press enter to continue or " + "ctrl+c to abort.") + except KeyboardInterrupt: + print() + print("Aborting...") + sys.exit(0) + if options.start is not None: + try: + options.start = pytz.utc.localize( + datetime.strptime(options.start, "%Y-%m-%d %H:%M:%S") + ) + except: + raise Exception("OptionsError: Failed to parse start datetime, make sure you use " + "'yyyy-mm-dd HH:MM:SS' format.") + if options.end is not None: + try: + options.end = pytz.utc.localize(datetime.strptime(options.end, "%Y-%m-%d %H:%M:%S")) + except: + raise Exception("OptionsError: Failed to parse end datetime, make sure you use " + "'yyyy-mm-dd HH:MM:SS' format.") + return options + return handle_options(options) + def main(): - """Placeholder for CLI.""" - print("There is no CLI for this module yet.") - sys.exit() + """Load CLI options and access the API accordingly.""" + options = parse_options() + pvl = PVLive() + if options.start is None and options.end is None: + data = pvl.latest(entity_type=options.entity_type, entity_id=options.entity_id, + extra_fields="installedcapacity_mwp", dataframe=True) + else: + start = datetime(2014, 1, 1, 0, 30, tzinfo=pytz.utc) if options.start is None \ + else options.start + end = pytz.utc.localize(datetime.utcnow()) if options.end is None else options.end + data = pvl.between(start, end, entity_type=options.entity_type, entity_id=options.entity_id, + extra_fields="installedcapacity_mwp", dataframe=True) + if options.outfile is not None: + data.to_csv(options.outfile, float_format="%.3f", index=False) + if not options.quiet: + print(data) if __name__ == "__main__": main() diff --git a/setup.py b/setup.py index 31d4216..9132d94 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version="0.7", + version="0.8", description="A Python interface for the PV_Live web API from Sheffield Solar.", long_description=long_description, @@ -113,7 +113,7 @@ # pip to create the appropriate form of executable for the target platform. entry_points={ "console_scripts": [ - + "pv_live = pvlive_api.pvlive:main", ], }, )