From 82e8c89f6e78685d3b83510d7e7e5a59208f99a6 Mon Sep 17 00:00:00 2001 From: Ian Black Date: Mon, 10 Nov 2025 13:19:43 -0800 Subject: [PATCH] Add functionality for more descriptive console messages and returning requests objects. --- scratch.ipynb | 2121 ++++++++++++++++++++++++++++++ src/onc/modules/_Messages.py | 86 ++ src/onc/modules/_MultiPage.py | 83 +- src/onc/modules/_OncArchive.py | 5 +- src/onc/modules/_OncDelivery.py | 4 +- src/onc/modules/_OncDiscovery.py | 5 +- src/onc/modules/_OncRealTime.py | 6 +- src/onc/modules/_OncService.py | 107 +- src/onc/modules/_util.py | 1 + src/onc/onc.py | 34 +- 10 files changed, 2351 insertions(+), 101 deletions(-) create mode 100644 scratch.ipynb create mode 100644 src/onc/modules/_Messages.py diff --git a/scratch.ipynb b/scratch.ipynb new file mode 100644 index 0000000..06646c4 --- /dev/null +++ b/scratch.ipynb @@ -0,0 +1,2121 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2025-11-10T21:17:04.711252Z", + "start_time": "2025-11-10T21:17:04.581618Z" + } + }, + "source": [ + "from netrc import netrc\n", + "from onc import ONC\n", + "\n", + "_, __, token = netrc().authenticators('data.oceannetworks.ca')" + ], + "outputs": [], + "execution_count": 1 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "## Initialization", + "id": "ef917e2e8133e385" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:17:04.722824Z", + "start_time": "2025-11-10T21:17:04.717615Z" + } + }, + "cell_type": "code", + "source": [ + "message_level = 'DEBUG' # Prints all messages to console.\n", + "redact_token = True # Removes a users token from console messages if set to True.\n", + "raise_http_errors = False # Does not raise HTTPError and instead returns the full requests.Response object.\n", + "\n", + "onc = ONC(token = token, verbosity = message_level, redact_token=redact_token, raise_http_errors=raise_http_errors)" + ], + "id": "f762aa13502fee66", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-11-10T21:17:04.720Z | onc-client | DEBUG | Initialized ONC module.\n" + ] + } + ], + "execution_count": 2 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:00:57.054214Z", + "start_time": "2025-11-10T21:00:57.049825Z" + } + }, + "cell_type": "markdown", + "source": "## OK Discovery Example", + "id": "9b3a0033f2f05f6b" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:17:05.247467Z", + "start_time": "2025-11-10T21:17:04.729847Z" + } + }, + "cell_type": "code", + "source": [ + "locs = onc.getLocationsTree({'locationCode': 'BCF'})\n", + "locs" + ], + "id": "5e6ed0b663a30da0", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-11-10T21:17:05.232Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/locations?locationCode=BCF&method=getTree&token=REDACTED\n", + "2025-11-10T21:17:05.232Z | onc-service | DEBUG | Response received in 0.5 seconds.\n", + "2025-11-10T21:17:05.232Z | onc-service | INFO | HTTP Response: OK (200)\n" + ] + }, + { + "data": { + "text/plain": [ + "[{'locationName': 'British Columbia Ferries',\n", + " 'children': [{'locationName': 'Campbell River - Quathiaski Cove Ferry Route',\n", + " 'children': None,\n", + " 'description': 'This ferry route goes between Campbell River, Vancouver Island, BC, and Quadra Island (Quathiaski Cove), BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'CRQC',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Horseshoe Bay - Departure Bay Ferry Route',\n", + " 'children': [{'locationName': 'GNSS V104S GPS',\n", + " 'children': None,\n", + " 'description': None,\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'HBDB.N1',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Thrane and Thrane SAILOR',\n", + " 'children': None,\n", + " 'description': None,\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'HBDB.N2',\n", + " 'hasPropertyData': False}],\n", + " 'description': 'This ferry route goes between Horseshoe Bay terminal in West Vancouver, BC and the Departure Bay terminal, Nanaimo BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'HBDB',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Nanaimo Harbour - Descanso Bay Ferry Route',\n", + " 'children': None,\n", + " 'description': 'This ferry route goes between Nanaimo Harbour terminal in Nanaimo, BC and the Descanso Bay terminal on Gabriola Island, BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'NHDB',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Port McNeill - Alert Bay - Sointula Ferry Route',\n", + " 'children': None,\n", + " 'description': 'This ferry route goes between Cormorant Island (Alert Bay), BC, Port McNeill, BC and Malcolm Island (Sointula), BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'PMABS',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Tsawwassen - Duke Point Ferry Route',\n", + " 'children': [{'locationName': 'GNSS MV104S GPS',\n", + " 'children': None,\n", + " 'description': '',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWDP.N1',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Thrane and Thrane SAILOR',\n", + " 'children': None,\n", + " 'description': None,\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWDP.N2',\n", + " 'hasPropertyData': False}],\n", + " 'description': 'This ferry route goes between Tsawwassen terminal in Vancouver, BC and the Duke Point terminal, Nanaimo BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWDP',\n", + " 'hasPropertyData': True},\n", + " {'locationName': 'Tsawwassen - Swartz Bay Ferry Route',\n", + " 'children': [{'locationName': 'Fluorometer Secondary',\n", + " 'children': None,\n", + " 'description': '',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWSB.F1',\n", + " 'hasPropertyData': False},\n", + " {'locationName': 'GNSS V104S GPS',\n", + " 'children': None,\n", + " 'description': None,\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWSB.N1',\n", + " 'hasPropertyData': False},\n", + " {'locationName': 'Thrane and Thrane SAILOR',\n", + " 'children': None,\n", + " 'description': None,\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWSB.N2',\n", + " 'hasPropertyData': False}],\n", + " 'description': 'This ferry route goes between Tsawwassen terminal in Vancouver, BC and the Swartz Bay terminal, Victoria BC.',\n", + " 'hasDeviceData': True,\n", + " 'locationCode': 'TWSB',\n", + " 'hasPropertyData': True}],\n", + " 'description': ' A few ferry vessels in the Salish Sea have been equipped with scientific instruments. Data is collected from routes between Vancouver Island and the mainland of British Columbia. Data is transmitted to Ocean Networks Canada shore stations via a wireless connection.',\n", + " 'hasDeviceData': False,\n", + " 'locationCode': 'BCF',\n", + " 'hasPropertyData': False}]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 3 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "## Not Found Discovery Example", + "id": "f983589d8201f9d3" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:17:06.001885Z", + "start_time": "2025-11-10T21:17:05.290709Z" + } + }, + "cell_type": "code", + "source": [ + "locs = onc.getLocations({'locationCode': 'BCF',\n", + " 'dateFrom': '2000-01-01T00:00:00.000Z',\n", + " 'dateTo': '2000-01-01T23:59:59.999Z'})\n", + "locs.status_code # Output is a requests.Response object instead of a raised HTTPError" + ], + "id": "5e9b97e55e7b9419", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-11-10T21:17:05.992Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/locations?locationCode=BCF&dateFrom=2000-01-01T00%3A00%3A00.000Z&dateTo=2000-01-01T23%3A59%3A59.999Z&method=get&token=REDACTED\n", + "2025-11-10T21:17:05.992Z | onc-service | DEBUG | Response received in 0.695 seconds.\n", + "2025-11-10T21:17:05.992Z | onc-service | ERROR | HTTP Response: Not Found (404)\n", + "2025-11-10T21:17:05.992Z | onc-service | ERROR | No metadata/data found for the given query parameters. Check if parameter input is valid.\n" + ] + }, + { + "data": { + "text/plain": [ + "404" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 4 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "## OK Data Example", + "id": "4c7c24a4da781d60" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:18:00.702793Z", + "start_time": "2025-11-10T21:17:54.596415Z" + } + }, + "cell_type": "code", + "source": [ + "data = onc.getScalardata({'locationCode':'BACVP',\n", + " 'deviceCategoryCode':'CTD',\n", + " 'dateFrom': '2009-08-20T00:00:00.000Z',\n", + " 'dateTo': '2009-08-29T23:59:59.999Z',\n", + " 'rowLimit': 10}, allPages = True)\n", + "data['sensorData']" + ], + "id": "16e99050e0ab4c0a", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-11-10T21:17:55.210Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-20T00%3A00%3A00.000Z&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&method=getByLocation&token=REDACTED\n", + "2025-11-10T21:17:55.213Z | onc-service | DEBUG | Response received in 0.608 seconds.\n", + "2025-11-10T21:17:55.213Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:55.217Z | onc-multi | INFO | The requested data quantity is greater than the supplied row limit and will be downloaded over multiple requests.\n", + "2025-11-10T21:17:55.219Z | onc-multi | DEBUG | Download time for page 1: 0.61 seconds\n", + "2025-11-10T21:17:55.222Z | onc-multi | INFO | Est. number of pages remaining for download: 114332\n", + "2025-11-10T21:17:55.222Z | onc-multi | INFO | Est. number of seconds to download remaining data: 19 hours\n", + "2025-11-10T21:17:55.223Z | onc-multi | DEBUG | Submitting request for page 2 (10 samples)...\n", + "2025-11-10T21:17:55.852Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A53%3A32.289Z&token=REDACTED\n", + "2025-11-10T21:17:55.852Z | onc-service | DEBUG | Response received in 0.626 seconds.\n", + "2025-11-10T21:17:55.852Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:55.858Z | onc-multi | DEBUG | Submitting request for page 3 (20 samples)...\n", + "2025-11-10T21:17:56.461Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A54%3A33.083Z&token=REDACTED\n", + "2025-11-10T21:17:56.461Z | onc-service | DEBUG | Response received in 0.607 seconds.\n", + "2025-11-10T21:17:56.471Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:56.471Z | onc-multi | DEBUG | Submitting request for page 4 (30 samples)...\n", + "2025-11-10T21:17:57.100Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A55%3A33.075Z&token=REDACTED\n", + "2025-11-10T21:17:57.100Z | onc-service | DEBUG | Response received in 0.625 seconds.\n", + "2025-11-10T21:17:57.100Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:57.107Z | onc-multi | DEBUG | Submitting request for page 5 (40 samples)...\n", + "2025-11-10T21:17:57.697Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A56%3A32.975Z&token=REDACTED\n", + "2025-11-10T21:17:57.707Z | onc-service | DEBUG | Response received in 0.593 seconds.\n", + "2025-11-10T21:17:57.707Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:57.707Z | onc-multi | DEBUG | Submitting request for page 6 (50 samples)...\n", + "2025-11-10T21:17:58.271Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A57%3A32.881Z&token=REDACTED\n", + "2025-11-10T21:17:58.271Z | onc-service | DEBUG | Response received in 0.556 seconds.\n", + "2025-11-10T21:17:58.271Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:58.271Z | onc-multi | DEBUG | Submitting request for page 7 (60 samples)...\n", + "2025-11-10T21:17:58.833Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A58%3A32.891Z&token=REDACTED\n", + "2025-11-10T21:17:58.833Z | onc-service | DEBUG | Response received in 0.555 seconds.\n", + "2025-11-10T21:17:58.833Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:58.833Z | onc-multi | DEBUG | Submitting request for page 8 (70 samples)...\n", + "2025-11-10T21:17:59.440Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T00%3A59%3A32.886Z&token=REDACTED\n", + "2025-11-10T21:17:59.440Z | onc-service | DEBUG | Response received in 0.597 seconds.\n", + "2025-11-10T21:17:59.440Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:17:59.440Z | onc-multi | DEBUG | Submitting request for page 9 (80 samples)...\n", + "2025-11-10T21:18:00.066Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T01%3A00%3A32.910Z&token=REDACTED\n", + "2025-11-10T21:18:00.066Z | onc-service | DEBUG | Response received in 0.619 seconds.\n", + "2025-11-10T21:18:00.066Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:18:00.074Z | onc-multi | DEBUG | Submitting request for page 10 (90 samples)...\n", + "2025-11-10T21:18:00.676Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?method=getByLocation&dateTo=2009-08-29T23%3A59%3A59.999Z&rowLimit=10&locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-27T01%3A01%3A32.909Z&token=REDACTED\n", + "2025-11-10T21:18:00.676Z | onc-service | DEBUG | Response received in 0.6 seconds.\n", + "2025-11-10T21:18:00.676Z | onc-service | INFO | HTTP Response: OK (200)\n", + "2025-11-10T21:18:00.687Z | onc-multi | INFO | Downloaded 94 total samples in 6 seconds.\n" + ] + }, + { + "data": { + "text/plain": [ + "[{'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [3.35513,\n", + " 3.35514,\n", + " 3.35505,\n", + " 3.35503,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35511,\n", + " 3.35509,\n", + " 3.35506,\n", + " 3.35504,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35504,\n", + " 3.35507,\n", + " 3.35511,\n", + " 3.35513,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35501,\n", + " 3.35496,\n", + " 3.35495,\n", + " 3.35499,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35499,\n", + " 3.35498,\n", + " 3.35496,\n", + " 3.35485,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35488,\n", + " 3.35482,\n", + " 3.35477,\n", + " 3.35476,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35476,\n", + " 3.35473,\n", + " 3.35464,\n", + " 3.3546,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35469,\n", + " 3.35464,\n", + " 3.35463,\n", + " 3.35456,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35466,\n", + " 3.35465,\n", + " 3.35462,\n", + " 3.35463,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 3.35462,\n", + " 3.35461,\n", + " 3.3546,\n", + " 3.35458]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'conductivity',\n", + " 'sensorCategoryCode': 'conductivity',\n", + " 'sensorCode': 'cond',\n", + " 'sensorName': 'Conductivity',\n", + " 'unitOfMeasure': 'S/m'},\n", + " {'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [393.13,\n", + " 397.98,\n", + " 388.16,\n", + " 387.96,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 457.53,\n", + " 426.99,\n", + " 422.17,\n", + " 403.53,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 342.4,\n", + " 384.93,\n", + " 633.38,\n", + " 701.15,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 305.69,\n", + " 186.96,\n", + " 205.94,\n", + " 268.58,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 326.42,\n", + " 247.48,\n", + " 231.35,\n", + " 214.03,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 316.57,\n", + " 265.31,\n", + " 258.51,\n", + " 255.77,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 317.38,\n", + " 272.14,\n", + " 269.27,\n", + " 266.25,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 338.83,\n", + " 277.15,\n", + " 273.76,\n", + " 271.97,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 339.87,\n", + " 279.94,\n", + " 277.44,\n", + " 274.57,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 340.92,\n", + " 281.16,\n", + " 279.27,\n", + " 277.16]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'depth',\n", + " 'sensorCategoryCode': 'depth',\n", + " 'sensorCode': 'depth',\n", + " 'sensorName': 'Depth',\n", + " 'unitOfMeasure': 'm'},\n", + " {'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [396.856,\n", + " 401.752,\n", + " 391.834,\n", + " 391.625,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 461.933,\n", + " 431.072,\n", + " 426.201,\n", + " 407.362,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 345.595,\n", + " 388.571,\n", + " 639.748,\n", + " 708.315,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 308.518,\n", + " 188.634,\n", + " 207.793,\n", + " 271.046,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 329.454,\n", + " 249.735,\n", + " 233.447,\n", + " 215.966,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 319.506,\n", + " 267.735,\n", + " 260.868,\n", + " 258.11,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 320.33,\n", + " 274.635,\n", + " 271.74,\n", + " 268.684,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 341.994,\n", + " 279.7,\n", + " 276.276,\n", + " 274.464,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 343.043,\n", + " 282.517,\n", + " 279.985,\n", + " 277.087,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 344.1,\n", + " 283.742,\n", + " 281.84,\n", + " 279.701]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'pressure',\n", + " 'sensorCategoryCode': 'pressure',\n", + " 'sensorCode': 'Pressure',\n", + " 'sensorName': 'Pressure',\n", + " 'unitOfMeasure': 'decibar'},\n", + " {'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [34.0584,\n", + " 34.0562,\n", + " 34.0601,\n", + " 34.06,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0262,\n", + " 34.0414,\n", + " 34.0432,\n", + " 34.0523,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0837,\n", + " 34.0627,\n", + " 33.9396,\n", + " 33.9069,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.1021,\n", + " 34.1618,\n", + " 34.152,\n", + " 34.1208,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0914,\n", + " 34.1315,\n", + " 34.1392,\n", + " 34.1472,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0973,\n", + " 34.1225,\n", + " 34.1254,\n", + " 34.1267,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0975,\n", + " 34.12,\n", + " 34.1205,\n", + " 34.1217,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0859,\n", + " 34.1166,\n", + " 34.1181,\n", + " 34.1183,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.085,\n", + " 34.1149,\n", + " 34.1161,\n", + " 34.1175,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 34.0847,\n", + " 34.1148,\n", + " 34.1156,\n", + " 34.1165]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'salinity',\n", + " 'sensorCategoryCode': 'salinity',\n", + " 'sensorCode': 'salinity',\n", + " 'sensorName': 'Practical Salinity',\n", + " 'unitOfMeasure': 'psu'},\n", + " {'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [26.83482199383866,\n", + " 26.833135110028707,\n", + " 26.836124468444496,\n", + " 26.83604313520459,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.810075942027424,\n", + " 26.821797794790882,\n", + " 26.82314384078154,\n", + " 26.830136239442254,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.854376133816686,\n", + " 26.838231537027696,\n", + " 26.743609425131126,\n", + " 26.7185395999486,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.868567078853857,\n", + " 26.914495190317666,\n", + " 26.906947076811548,\n", + " 26.88296826678652,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.860317002403917,\n", + " 26.89120368114618,\n", + " 26.897095706605114,\n", + " 26.90329931409292,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.865147630873935,\n", + " 26.884512111930007,\n", + " 26.886732587094002,\n", + " 26.887743736117272,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.86554888761725,\n", + " 26.88285528766187,\n", + " 26.88323232524158,\n", + " 26.884161211195078,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.856607287764973,\n", + " 26.88023273309932,\n", + " 26.881382567675928,\n", + " 26.88153385031319,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.855906804638153,\n", + " 26.878868945131217,\n", + " 26.879828027172834,\n", + " 26.8808920177878,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 26.85576714051558,\n", + " 26.878938635334407,\n", + " 26.879538725086377,\n", + " 26.880227723996086]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'sigmatheta',\n", + " 'sensorCategoryCode': 'sigma_theta',\n", + " 'sensorCode': 'SIGMA_THETA',\n", + " 'sensorName': 'Sigma-theta (0 dbar)',\n", + " 'unitOfMeasure': 'kg/m3'},\n", + " {'actualSamples': 3,\n", + " 'data': {'qaqcFlags': [0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 9,\n", + " 0,\n", + " 0,\n", + " 0,\n", + " 0],\n", + " 'sampleTimes': ['2009-08-27T00:53:29.800Z',\n", + " '2009-08-27T00:53:30.043Z',\n", + " '2009-08-27T00:53:30.289Z',\n", + " '2009-08-27T00:53:30.539Z',\n", + " '2009-08-27T00:53:30.789Z',\n", + " '2009-08-27T00:53:31.039Z',\n", + " '2009-08-27T00:53:31.289Z',\n", + " '2009-08-27T00:53:31.539Z',\n", + " '2009-08-27T00:53:31.789Z',\n", + " '2009-08-27T00:53:32.039Z',\n", + " '2009-08-27T00:54:30.585Z',\n", + " '2009-08-27T00:54:30.834Z',\n", + " '2009-08-27T00:54:31.084Z',\n", + " '2009-08-27T00:54:31.333Z',\n", + " '2009-08-27T00:54:31.583Z',\n", + " '2009-08-27T00:54:31.833Z',\n", + " '2009-08-27T00:54:32.083Z',\n", + " '2009-08-27T00:54:32.333Z',\n", + " '2009-08-27T00:54:32.583Z',\n", + " '2009-08-27T00:54:32.833Z',\n", + " '2009-08-27T00:55:30.578Z',\n", + " '2009-08-27T00:55:30.827Z',\n", + " '2009-08-27T00:55:31.077Z',\n", + " '2009-08-27T00:55:31.325Z',\n", + " '2009-08-27T00:55:31.575Z',\n", + " '2009-08-27T00:55:31.825Z',\n", + " '2009-08-27T00:55:32.075Z',\n", + " '2009-08-27T00:55:32.325Z',\n", + " '2009-08-27T00:55:32.575Z',\n", + " '2009-08-27T00:55:32.825Z',\n", + " '2009-08-27T00:56:30.597Z',\n", + " '2009-08-27T00:56:30.847Z',\n", + " '2009-08-27T00:56:31.033Z',\n", + " '2009-08-27T00:56:31.225Z',\n", + " '2009-08-27T00:56:31.475Z',\n", + " '2009-08-27T00:56:31.725Z',\n", + " '2009-08-27T00:56:31.975Z',\n", + " '2009-08-27T00:56:32.225Z',\n", + " '2009-08-27T00:56:32.475Z',\n", + " '2009-08-27T00:56:32.725Z',\n", + " '2009-08-27T00:57:30.380Z',\n", + " '2009-08-27T00:57:30.631Z',\n", + " '2009-08-27T00:57:30.882Z',\n", + " '2009-08-27T00:57:31.131Z',\n", + " '2009-08-27T00:57:31.381Z',\n", + " '2009-08-27T00:57:31.631Z',\n", + " '2009-08-27T00:57:31.881Z',\n", + " '2009-08-27T00:57:32.131Z',\n", + " '2009-08-27T00:57:32.381Z',\n", + " '2009-08-27T00:57:32.631Z',\n", + " '2009-08-27T00:58:30.387Z',\n", + " '2009-08-27T00:58:30.638Z',\n", + " '2009-08-27T00:58:30.889Z',\n", + " '2009-08-27T00:58:31.141Z',\n", + " '2009-08-27T00:58:31.391Z',\n", + " '2009-08-27T00:58:31.641Z',\n", + " '2009-08-27T00:58:31.891Z',\n", + " '2009-08-27T00:58:32.141Z',\n", + " '2009-08-27T00:58:32.391Z',\n", + " '2009-08-27T00:58:32.641Z',\n", + " '2009-08-27T00:59:30.389Z',\n", + " '2009-08-27T00:59:30.639Z',\n", + " '2009-08-27T00:59:30.888Z',\n", + " '2009-08-27T00:59:31.136Z',\n", + " '2009-08-27T00:59:31.386Z',\n", + " '2009-08-27T00:59:31.636Z',\n", + " '2009-08-27T00:59:31.886Z',\n", + " '2009-08-27T00:59:32.136Z',\n", + " '2009-08-27T00:59:32.386Z',\n", + " '2009-08-27T00:59:32.636Z',\n", + " '2009-08-27T01:00:30.407Z',\n", + " '2009-08-27T01:00:30.657Z',\n", + " '2009-08-27T01:00:30.907Z',\n", + " '2009-08-27T01:00:31.160Z',\n", + " '2009-08-27T01:00:31.410Z',\n", + " '2009-08-27T01:00:31.660Z',\n", + " '2009-08-27T01:00:31.910Z',\n", + " '2009-08-27T01:00:32.160Z',\n", + " '2009-08-27T01:00:32.410Z',\n", + " '2009-08-27T01:00:32.660Z',\n", + " '2009-08-27T01:01:30.408Z',\n", + " '2009-08-27T01:01:30.657Z',\n", + " '2009-08-27T01:01:30.909Z',\n", + " '2009-08-27T01:01:31.159Z',\n", + " '2009-08-27T01:01:31.409Z',\n", + " '2009-08-27T01:01:31.659Z',\n", + " '2009-08-27T01:01:31.909Z',\n", + " '2009-08-27T01:01:32.159Z',\n", + " '2009-08-27T01:01:32.409Z',\n", + " '2009-08-27T01:01:32.659Z',\n", + " '2009-08-27T01:02:30.424Z',\n", + " '2009-08-27T01:02:30.674Z',\n", + " '2009-08-27T01:02:30.923Z',\n", + " '2009-08-27T01:02:31.173Z'],\n", + " 'values': [5.8232,\n", + " 5.8232,\n", + " 5.8231,\n", + " 5.8231,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8231,\n", + " 5.8228,\n", + " 5.823,\n", + " 5.823,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8224,\n", + " 5.8224,\n", + " 5.8226,\n", + " 5.8224,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8221,\n", + " 5.8222,\n", + " 5.8222,\n", + " 5.822,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8222,\n", + " 5.822,\n", + " 5.8222,\n", + " 5.8217,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.82,\n", + " 5.8201,\n", + " 5.8201,\n", + " 5.82,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8181,\n", + " 5.8181,\n", + " 5.818,\n", + " 5.8179,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8181,\n", + " 5.818,\n", + " 5.818,\n", + " 5.8179,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8181,\n", + " 5.8184,\n", + " 5.8181,\n", + " 5.8182,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " nan,\n", + " 5.8174,\n", + " 5.8173,\n", + " 5.8174,\n", + " 5.8174]},\n", + " 'outputFormat': 'array',\n", + " 'propertyCode': 'seawatertemperature',\n", + " 'sensorCategoryCode': 'temperature',\n", + " 'sensorCode': 'Temperature',\n", + " 'sensorName': 'Temperature',\n", + " 'unitOfMeasure': 'C'}]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 7 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:10:51.298653Z", + "start_time": "2025-11-10T21:10:51.282654Z" + } + }, + "cell_type": "markdown", + "source": "## Bad Data Request Example", + "id": "5c3b637cf29f849f" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-10T21:17:12.631455Z", + "start_time": "2025-11-10T21:17:12.280322Z" + } + }, + "cell_type": "code", + "source": [ + "data = onc.getScalardata({'locationCode':'BACVP',\n", + " 'deviceCategoryCode':'CTD',\n", + " 'dateFrom': '2009-08-15T00:00:00.000Z',\n", + " 'dateTo': '2009-08-17T23:59:59.999Z',\n", + " 'rowLimit': 10}, allPages = True)\n", + "\n", + "if isinstance(data, dict):\n", + " print(data)\n", + "else: # Assume it is a requests.Response object.\n", + " print(data.status_code)" + ], + "id": "d27aaa83f916109e", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-11-10T21:17:12.620Z | onc-service | INFO | Requested: https://data.oceannetworks.ca/api/scalardata?locationCode=BACVP&deviceCategoryCode=CTD&dateFrom=2009-08-15T00%3A00%3A00.000Z&dateTo=2009-08-17T23%3A59%3A59.999Z&rowLimit=10&method=getByLocation&token=REDACTED\n", + "2025-11-10T21:17:12.620Z | onc-service | DEBUG | Response received in 0.341 seconds.\n", + "2025-11-10T21:17:12.620Z | onc-service | ERROR | HTTP Response: Bad Request (400)\n", + "2025-11-10T21:17:12.620Z | onc-service | ERROR | (API Error Code 127) A device with category CTD was deployed at location BACVP but not during the provided time range (20090815T000000.000Z to 20090817T235959.999Z). The deployment service can be used to determine a valid time range: https://data.oceannetworks.ca/api/deployments?locationCode=BACVP&deviceCategoryCode=CTD&token=REDACTED for query parameter(s) 'locationCode, deviceCategoryCode, dateFrom, dateTo'.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "400\n" + ] + } + ], + "execution_count": 6 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/onc/modules/_Messages.py b/src/onc/modules/_Messages.py new file mode 100644 index 0000000..19b1ada --- /dev/null +++ b/src/onc/modules/_Messages.py @@ -0,0 +1,86 @@ +import logging +import re +import requests +import time + +REQ_MSG = "Requested: {}" # get request url +RESPONSE_TIME_MSG = "Response received in {} seconds." # requests.elapsed value. +RESPONSE_MSG = "HTTP Response: {} ({})" # Brief description, status code +MULTIPAGE_MSG = ("The requested data quantity is greater than the " + "supplied row limit and will be downloaded over multiple requests.") + + +def setup_logger(logger_name: str = 'onc-client', + level: int | str = 'DEBUG') -> logging.Logger: + """ + Set up a logger object for displaying verbose messages to console. + + :param logger_name: The unique logger name to use. Can be shared between modules + :param level: The logging level to use. Default is 2, which corresponds to DEBUG. + :return: The configured logging.Logger object. + """ + + logger = logging.getLogger(logger_name) + logger.propagate = False + if not logger.handlers: + logger.setLevel(logging.DEBUG) + console = logging.StreamHandler() + console.setLevel(level) + + # Set the logging format. + dtfmt = '%Y-%m-%dT%H:%M:%S' + strfmt = f'%(asctime)s.%(msecs)03dZ | %(name)-12s | %(levelname)-8s | %(message)s' + #strfmt = f'%(asctime)s.%(msecs)03dZ | %(levelname)-8s | %(message)s' # Use this if you don't want to include logger name. + fmt = logging.Formatter(strfmt, datefmt=dtfmt) + fmt.converter = time.gmtime + + console.setFormatter(fmt) + logger.addHandler(console) + return logger + + +def scrub_token(input: str) -> str: + """ + Replace a token in a query URL or other string with the string 'REDACTED' + so that users don't accidentally commit their tokens to public repositories + if ONC Info/Warnings are too verbose. + + :param query_url: An Oceans 3.0 API URL or string with a token query parameter. + :return: A scrubbed url. + """ + token_regex = r'(&token=[a-f0-9-]{36})' + token_qp = re.findall(token_regex, input)[0] + redacted_url = input.replace(token_qp, '&token=REDACTED') + return redacted_url + + +def build_error_message(response: requests.Response, redact_token: bool) -> str: + """ + Build an error message from a requests.Response object. + + :param response: A requests.Response object. + :param redact_token: If true, redact tokens before returning an error message. + :return: An error message. + """ + payload = response.json() + if 'message' in payload.keys(): + message = payload['message'] + else: + message = None + + if 'errors' in payload.keys(): + errors = payload['errors'] + error_messages = [] + for error in errors: + emsg = (f"(API Error Code {error['errorCode']}) " + f"{error['errorMessage']} for query parameter(s) " + f"'{error['parameter']}'.") + error_messages.append(emsg) + error_message = '\n'.join(error_messages) + else: + error_message = None + msg = '\n'.join([m for m in (message, error_message) if m is not None]) + if redact_token is True and 'token=' in msg: + msg = scrub_token(msg) + return msg + diff --git a/src/onc/modules/_MultiPage.py b/src/onc/modules/_MultiPage.py index 1443234..26ae55e 100644 --- a/src/onc/modules/_MultiPage.py +++ b/src/onc/modules/_MultiPage.py @@ -8,12 +8,23 @@ from ._util import _formatDuration +from onc.modules._Messages import (setup_logger, MULTIPAGE_MSG, + build_error_message, + scrub_token, + REQ_MSG, + RESPONSE_TIME_MSG, + RESPONSE_MSG) + + # Handles data multi-page downloads (scalardata, rawdata, archivefiles) class _MultiPage: - def __init__(self, parent: object): + def __init__(self, parent: object, verbosity: bool, raise_http_errors: bool): self.parent = weakref.ref(parent) self.result = None + self.raise_http_errors = raise_http_errors + self.__log = setup_logger('onc-multi', verbosity) + def getAllPages(self, service: str, url: str, filters: dict): """ @@ -30,48 +41,42 @@ def getAllPages(self, service: str, url: str, filters: dict): # download first page start = time() response, responseTime = self._doPageRequest(url, filters, service, extension) - rNext = response["next"] - - if rNext is not None: - print( - "Data quantity is greater than the row limit and", - "will be downloaded in multiple pages.", - ) - - pageCount = 1 - pageEstimate = self._estimatePages(response, service) - if pageEstimate > 0: - # Exclude the first page when calculating the time estimation - timeEstimate = _formatDuration((pageEstimate - 1) * responseTime) - print( - f"Downloading time for the first page: {humanize.naturaldelta(responseTime)}" # noqa: E501 - ) - print(f"Estimated approx. {pageEstimate} pages in total.") - print( - f"Estimated approx. {timeEstimate} to complete for the rest of the pages." # noqa: E501 - ) - # keep downloading pages until next is None - print("") - while rNext is not None: - pageCount += 1 - rowCount = self._rowCount(response, service) + if isinstance(response,dict): + rNext = response["next"] - print(f" ({rowCount} samples) Downloading page {pageCount}...") - nextResponse, nextTime = self._doPageRequest( - url, rNext["parameters"], service, extension - ) - rNext = nextResponse["next"] + if rNext is not None: + self.__log.info("The requested data quantity is greater than the supplied " + "row limit and will be downloaded over multiple requests.") + + pageCount = 1 + pageEstimate = self._estimatePages(response, service) + if pageEstimate > 0: + # Exclude the first page when calculating the time estimation + timeEstimate = _formatDuration((pageEstimate - 1) * responseTime) + self.__log.debug(f'Download time for page {pageCount}: {round(responseTime,2)} seconds') + self.__log.info(f'Est. number of pages remaining for download: {pageEstimate-1}') + self.__log.info(f'Est. number of seconds to download remaining data: {timeEstimate}') + + # keep downloading pages until next is None + while rNext is not None: + pageCount += 1 + rowCount = self._rowCount(response, service) + + self.__log.debug(f"Submitting request for page {pageCount} ({rowCount} samples)...") + + nextResponse, nextTime = self._doPageRequest( + url, rNext["parameters"], service, extension + ) + rNext = nextResponse["next"] + + # concatenate new data obtained + self._catenateData(response, nextResponse, service) - # concatenate new data obtained - self._catenateData(response, nextResponse, service) + totalTime = _formatDuration(time() - start) - totalTime = _formatDuration(time() - start) - print( - f" ({self._rowCount(response, service):d} samples)" - f" Completed in {totalTime}." - ) - response["next"] = None + self.__log.info(f"Downloaded {self._rowCount(response, service):d} total samples in {totalTime}.") + response["next"] = None return response diff --git a/src/onc/modules/_OncArchive.py b/src/onc/modules/_OncArchive.py index ecc6e09..df7bf47 100644 --- a/src/onc/modules/_OncArchive.py +++ b/src/onc/modules/_OncArchive.py @@ -14,8 +14,9 @@ class _OncArchive(_OncService): Methods that wrap the API archivefiles service """ - def __init__(self, parent: object): - super().__init__(parent) + def __init__(self, parent: object, verbosity: str, redact_token: str, raise_http_errors: bool): + super().__init__(parent, verbosity, redact_token, raise_http_errors) + def getArchivefileByLocation(self, filters: dict, allPages: bool): """ diff --git a/src/onc/modules/_OncDelivery.py b/src/onc/modules/_OncDelivery.py index bc210b2..7908c8c 100644 --- a/src/onc/modules/_OncDelivery.py +++ b/src/onc/modules/_OncDelivery.py @@ -16,8 +16,8 @@ class _OncDelivery(_OncService): Methods that wrap the API data product delivery services """ - def __init__(self, parent: object): - super().__init__(parent) + def __init__(self, parent: object, verbosity: str, redact_token: str, raise_http_errors: bool): + super().__init__(parent, verbosity, redact_token, raise_http_errors) # Default seconds to wait between consecutive download tries of a file # (when no estimate processing time is available) diff --git a/src/onc/modules/_OncDiscovery.py b/src/onc/modules/_OncDiscovery.py index 297d3df..5b83b10 100644 --- a/src/onc/modules/_OncDiscovery.py +++ b/src/onc/modules/_OncDiscovery.py @@ -7,8 +7,9 @@ class _OncDiscovery(_OncService): locations, deployments, devices, deviceCategories, properties, dataProducts """ - def __init__(self, parent: object): - super().__init__(parent) + def __init__(self, parent: object, verbosity: str, redact_token: str, raise_http_errors: bool): + super().__init__(parent, verbosity, redact_token, raise_http_errors) + def _discoveryRequest(self, filters: dict, service: str, method: str = "get"): url = self._serviceUrl(service) diff --git a/src/onc/modules/_OncRealTime.py b/src/onc/modules/_OncRealTime.py index cad4386..2610cdb 100644 --- a/src/onc/modules/_OncRealTime.py +++ b/src/onc/modules/_OncRealTime.py @@ -9,8 +9,8 @@ class _OncRealTime(_OncService): Near real-time services methods """ - def __init__(self, config: dict): - super().__init__(config) + def __init__(self, config: dict, verbosity: str, redact_token: str, raise_http_errors: bool): + super().__init__(config, verbosity, redact_token, raise_http_errors) def getScalardataByLocation(self, filters: dict, allPages: bool): """ @@ -93,7 +93,7 @@ def _getDirectAllPages( filters["sensorCategoryCodes"] = ",".join(filters["sensorCategoryCodes"]) if allPages: - mp = _MultiPage(self) + mp = _MultiPage(self, self.verbosity, self.raise_http_errors) result = mp.getAllPages(service, url, filters) else: result = self._doRequest(url, filters) diff --git a/src/onc/modules/_OncService.py b/src/onc/modules/_OncService.py index a1d3c78..e3e6e96 100644 --- a/src/onc/modules/_OncService.py +++ b/src/onc/modules/_OncService.py @@ -9,6 +9,12 @@ import requests from ._util import _createErrorMessage, _formatDuration +from onc.modules._Messages import (setup_logger, + build_error_message, + scrub_token, + REQ_MSG, + RESPONSE_TIME_MSG, + RESPONSE_MSG) logging.basicConfig(format="%(levelname)s: %(message)s") @@ -18,8 +24,16 @@ class _OncService: Provides common configuration and functionality to Onc service classes (children) """ - def __init__(self, parent: object): + def __init__(self, parent: object, + verbosity: str, + redact_token: bool, + raise_http_errors: bool): self.parent = weakref.ref(parent) + self.redact_token = redact_token + self.raise_http_errors = raise_http_errors + self.verbosity = verbosity + + self.__log = setup_logger('onc-service', level = verbosity) def _doRequest(self, url: str, filters: dict | None = None, getTime: bool = False): """ @@ -46,48 +60,60 @@ def _doRequest(self, url: str, filters: dict | None = None, getTime: bool = Fals filters["token"] = self._config("token") timeout = self._config("timeout") - txtParams = parse.unquote(parse.urlencode(filters)) - self._log(f"Requesting URL:\n{url}?{txtParams}") - - start = time() response = requests.get(url, filters, timeout=timeout) - responseTime = time() - start - if response.ok: - jsonResult = response.json() + if self.redact_token is True: + try: + response_url = scrub_token(response.url) + except: + response_url = response.url else: - status = response.status_code - if status in [400, 401]: - msg = _createErrorMessage(response) - raise requests.HTTPError(msg) - else: - response.raise_for_status() - self._log(f"Web Service response time: {_formatDuration(responseTime)}") - - # Log warning messages only when showWarning is True - # and jsonResult["messages"] is not an empty list - if ( - self._config("showWarning") - and "messages" in jsonResult - and jsonResult["messages"] - ): - long_message = "\n".join( - [f"* {message}" for message in jsonResult["messages"]] - ) + response_url = response.url - filters_without_token = filters.copy() - del filters_without_token["token"] - filters_str = pprint.pformat(filters_without_token) + # Log the url the user submitted. + self.__log.info(REQ_MSG.format(response_url)) - logging.warning( - f"When calling {url} with filters\n{filters_str},\n" - f"there are several warning messages:\n{long_message}\n" - ) + # Display the time it took for ONC to respond in seconds. + # The requests.Response.elapsed value is a datetime.timedelta object. + responseTime = round(response.elapsed.total_seconds(),3) # To milliseconds. + self.__log.debug(RESPONSE_TIME_MSG.format(responseTime)) + + json_response = response.json() - if getTime: - return jsonResult, responseTime + if response.status_code == requests.codes.ok: + self.__log.info(RESPONSE_MSG.format("OK", response.status_code)) + if getTime is True: + return json_response, responseTime + else: + return json_response else: - return jsonResult + if response.status_code == requests.codes.not_found: + self.__log.error(RESPONSE_MSG.format("Not Found", + response.status_code)) + elif response.status_code == requests.codes.bad: + self.__log.error(RESPONSE_MSG.format("Bad Request", + response.status_code)) + elif response.status_code == requests.codes.unauthorized: + self.__log.error(RESPONSE_MSG.format("Unauthorized Request", + response.status_code)) + elif response.status_code == requests.codes.internal_server_error: + self.__log.error(RESPONSE_MSG.format("Internal Server Error", + response.status_code)) + else: + self.__log.error(RESPONSE_MSG.format('Error',response.status_code)) + + self.__log.error(build_error_message(response, + self.redact_token)) + + if self.raise_http_errors is True: + response.raise_for_status() + + else: + if getTime is True: + return response, responseTime + else: + return response + def _serviceUrl(self, service: str): """ @@ -109,14 +135,6 @@ def _serviceUrl(self, service: str): return "" - def _log(self, message: str): - """ - Prints message to console only when self.showInfo is true - @param message: String - """ - if self._config("showInfo"): - print(message) - def _config(self, key: str): """ Returns a property from the parent (ONC class) @@ -139,3 +157,4 @@ def _delegateByFilters(self, byDevice, byLocation, **kwargs): "'locationCode' and 'deviceCategoryCode', " "or a 'deviceCode' present." ) + diff --git a/src/onc/modules/_util.py b/src/onc/modules/_util.py index 16db3fb..e867205 100644 --- a/src/onc/modules/_util.py +++ b/src/onc/modules/_util.py @@ -76,6 +76,7 @@ def _createErrorMessage(response: requests.Response) -> str: elif status == 401: return ( f"Status 401 - Unauthorized: {response.url}\n" + "Please check that your Web Services API token is valid. " "Find your token in your registered profile at " "https://data.oceannetworks.ca." diff --git a/src/onc/onc.py b/src/onc/onc.py index 922f983..020e7fe 100644 --- a/src/onc/onc.py +++ b/src/onc/onc.py @@ -11,6 +11,7 @@ from onc.modules._OncDiscovery import _OncDiscovery from onc.modules._OncRealTime import _OncRealTime +from onc.modules._Messages import setup_logger class ONC: """ @@ -51,24 +52,39 @@ class ONC: def __init__( self, token, - production: bool = True, - showInfo: bool = False, - showWarning: bool = False, outPath: str | Path = "output", + verbosity: str = "INFO", + raise_http_errors: bool = True, + redact_token: bool = False, timeout: int = 60, + production: bool = True, ): + + self.verbosity = verbosity.upper() + self.redact_token = redact_token + self.raise_http_errors = raise_http_errors + self.__log = setup_logger('onc-client', self.verbosity) + + if self.verbosity in ['INFO', 'DEBUG']: + self.showInfo = True + self.showWarning = True + elif self.verbosity in ['WARNING', 'ERROR']: + self.showInfo = False + self.showWarning = True + self.token = re.sub(r"[^a-zA-Z0-9\-]+", "", token) - self.showInfo = showInfo - self.showWarning = showWarning + self.timeout = timeout self.production = production self.outPath = outPath # Create service objects - self.discovery = _OncDiscovery(self) - self.delivery = _OncDelivery(self) - self.realTime = _OncRealTime(self) - self.archive = _OncArchive(self) + self.discovery = _OncDiscovery(self, verbosity, redact_token,raise_http_errors) + self.delivery = _OncDelivery(self, verbosity, redact_token,raise_http_errors) + self.realTime = _OncRealTime(self, verbosity, redact_token,raise_http_errors) + self.archive = _OncArchive(self, verbosity, redact_token,raise_http_errors) + + self.__log.debug("Initialized ONC module.") @property def outPath(self) -> Path: