Files
ThingsBoard/Report Generator/email-reports.ipynb
2024-12-10 17:48:49 -06:00

1741 lines
78 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from tb_rest_client.rest_client_pe import *\n",
"from tb_rest_client.rest import ApiException\n",
"import json, xlsxwriter, boto3, os, time\n",
"from threading import Lock\n",
"from datetime import datetime as dt\n",
"from email.mime.multipart import MIMEMultipart\n",
"from email.mime.text import MIMEText\n",
"from email import encoders\n",
"from email.mime.base import MIMEBase"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Define a rate limiter class\n",
"class RateLimiter:\n",
" def __init__(self, max_calls, period):\n",
" self.max_calls = max_calls\n",
" self.period = period\n",
" self.call_times = []\n",
" self.lock = Lock()\n",
"\n",
" def acquire(self):\n",
" with self.lock:\n",
" current_time = time.time()\n",
" # Remove expired calls\n",
" self.call_times = [t for t in self.call_times if t > current_time - self.period]\n",
" if len(self.call_times) >= self.max_calls:\n",
" # Wait for the oldest call to expire\n",
" time_to_wait = self.period - (current_time - self.call_times[0])\n",
" time.sleep(time_to_wait)\n",
" # Register the current call\n",
" self.call_times.append(time.time())\n",
"\n",
"# Initialize a rate limiter\n",
"rate_limiter = RateLimiter(max_calls=10, period=1) # Adjust `max_calls` and `period` as needed\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"\n",
"def sort_dict_keys(d):\n",
" \"\"\"Sorts the keys of all nested dictionaries in a given dictionary.\n",
"\n",
" Args:\n",
" d: The input dictionary.\n",
"\n",
" Returns:\n",
" A new dictionary with sorted keys at each level.\n",
" \"\"\"\n",
" sorted_d = {}\n",
" for k, v in d.items():\n",
" if isinstance(v, dict):\n",
" sorted_d[k] = sort_dict_keys(v)\n",
" else:\n",
" sorted_d[k] = v\n",
" return dict(sorted(sorted_d.items()))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"url = \"https://hp.henrypump.cloud\"\n",
"username = \"nmelone@henry-pump.com\"\n",
"password = \"gzU6$26v42mU%3jDzTJf\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Creating Rest Client for ThingsBoard\n",
"with RestClientPE(base_url=url) as rest_client:\n",
" try:\n",
" rest_client.login(username=username, password=password)\n",
" # Loading Config from file\n",
" with open('/Users/nico/Documents/GitHub/ThingsBoard/Report Generator/lambda-python3.12/tbreport/config.json') as f:\n",
" config = json.load(f)\n",
" reportData = {}\n",
" reportToList = {}\n",
"\n",
" # Loop through each item in config, each item represents a report\n",
" for report in config:\n",
" reportToList[report[\"name\"]] = report[\"emails\"]\n",
" for customer in report[\"customers\"].keys():\n",
" # Apply rate limiting for API calls\n",
" rate_limiter.acquire()\n",
" devices = rest_client.get_customer_devices(customer_id=customer, page=0, page_size=1000)\n",
" \n",
" if report[\"filterDevicesIn\"]:\n",
" devices.data = [device for device in devices.data if device.id.id in report[\"filterDevicesIn\"]]\n",
" if report[\"filterDevicesOut\"]:\n",
" devices.data = [device for device in devices.data if device.id.id not in report[\"filterDevicesOut\"]]\n",
" \n",
" if not reportData.get(report[\"name\"], None):\n",
" reportData[report[\"name\"]] = {}\n",
"\n",
" for device in devices.data:\n",
" for deviceType in report[\"customers\"][customer][\"deviceTypes\"]:\n",
" if device.type == deviceType[\"deviceType\"]:\n",
" rate_limiter.acquire()\n",
" keys = rest_client.get_timeseries_keys_v1(device.id)\n",
" keys = list(filter(lambda x: x in deviceType[\"dataPoints\"], keys))\n",
" #Check for report customer\n",
" if not reportData[report[\"name\"]].get(report[\"customers\"][customer][\"name\"], None):\n",
" reportData[report[\"name\"]][report[\"customers\"][customer][\"name\"]] = {}\n",
" #Check for device type in config\n",
" if device.type in list(map(lambda x: x[\"deviceType\"], report[\"customers\"][customer][\"deviceTypes\"])):\n",
" #Check if deviceType in report\n",
" if not reportData[report[\"name\"]][report[\"customers\"][customer][\"name\"]].get(device.type, None):\n",
" reportData[report[\"name\"]][report[\"customers\"][customer][\"name\"]][device.type] = {}\n",
" if keys:\n",
" rate_limiter.acquire()\n",
" deviceData = rest_client.get_latest_timeseries(entity_id=device.id, keys=\",\".join(keys))\n",
" for x in report[\"customers\"][customer][\"deviceTypes\"]:\n",
" if x[\"deviceType\"] == device.type:\n",
" labels = x[\"labels\"]\n",
" labelled_data = {}\n",
" for k,v in labels.items():\n",
" labelled_data[v] = {}\n",
" for k,v in deviceData.items():\n",
" labelled_data[labels[k]] = v\n",
" reportData[report[\"name\"]][report[\"customers\"][customer][\"name\"]][device.type][device.name] = labelled_data\n",
" else:\n",
" reportData[report[\"name\"]][report[\"customers\"][customer][\"name\"]][device.type][device.name] = {} \n",
" #Sort Data\n",
" reportDataSorted = sort_dict_keys(reportData)\n",
" #print(json.dumps(reportDataSorted,indent=4))\n",
" except ApiException as e:\n",
" print(f\"API Exception: {e}\")\n",
" except Exception as e:\n",
" print(f\"Other Exception in getting data:\\n{e}\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\n",
" \"OxyRock-Daily-Report\": {\n",
" \"OxyRock\": {\n",
" \"advvfdipp\": {\n",
" \"ToolBox North\": {},\n",
" \"Wilkinson 33 SR 2-2\": {},\n",
" \"Nail Ranch 2 SR 3-3\": {},\n",
" \"ToolBox South\": {},\n",
" \"Wilkinson 35 SR 1-1\": {},\n",
" \"Wrage 21 SR 2-2\": {\n",
" \"Yesterday's Energy\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"856.13\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"2980.96\"\n",
" }\n",
" ],\n",
" \"Fluid Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"155.46\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"50.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"8.06\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wrage 33 SR 3-3\": {},\n",
" \"Wilkinson 37 WS 1-7\": {\n",
" \"Yesterday's Energy\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Fluid Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"124.98\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 1-8\": {\n",
" \"Yesterday's Energy\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Fluid Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"95.03\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Nail Ranch 28 SR 1-1\": {},\n",
" \"Nail Ranch 28 SR 3-3\": {},\n",
" \"Jones A\": {\n",
" \"Yesterday's Energy\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"975.56\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"2945.46\"\n",
" }\n",
" ],\n",
" \"Fluid Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"153.15\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"58.41\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"2.2\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 SR 1-1\": {}\n",
" },\n",
" \"rigpump\": {\n",
" \"Rig Pump #07\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #14\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #03\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #04\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #08\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #12\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732063200000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732063200000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #11\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Rig Pump #06\": {\n",
" \"VFD Frequency\": [\n",
" {\n",
" \"ts\": 1732126200000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"VFD Current\": [\n",
" {\n",
" \"ts\": 1732126200000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" }\n",
" },\n",
" \"piflow\": {\n",
" \"Horton 34 WS 1-2\": {},\n",
" \"Wilkinson 33 WS 10-4\": {},\n",
" \"Wilkinson 1 WS 2-10\": {},\n",
" \"Horton 23 WS 5-2\": {},\n",
" \"Wilkinson 39 WS 1-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1349168.625\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"341.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"42.89\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 1-6\": {},\n",
" \"Wilkinson 34 WS 9-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"9415.185546875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Horton 23 WS 5-5\": {},\n",
" \"Wilkinson 37 WS 5-5\": {\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"39.39\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"30.53\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 40 WS 1-1\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"276397.09375\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724952266773,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Horton 34 WS 1-4\": {},\n",
" \"Wilkinson 39 WS 3-8\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"2211196.25\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724952251453,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"896.5\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 34 WS 6-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1882162.375\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"54.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1707.25\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"39.56\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 1 WS 9-4B\": {},\n",
" \"Horton 34 WS 1-3\": {},\n",
" \"Wilkinson 39 WS 1-8\": {},\n",
" \"Free 40 WS 2-2\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1724951194678,\n",
" \"value\": \"1145504.125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724951224777,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1724951195757,\n",
" \"value\": \"1018.125\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1724951220664,\n",
" \"value\": \"64.08\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 7-8\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"928518.1875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"766.0625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 10-2\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1201432.875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"9.58\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 10-3B\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1444936.625\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"45.1\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1464.5\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"42.45\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 34 WS 9-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1108773.0\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1730846312852,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 1-3\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1786676.5\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724948196359,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1017.625\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 34 WS 10-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1192412.625\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"791.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Horton 23 WS 6-6\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1724950907908,\n",
" \"value\": \"1038938.75\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1724950908927,\n",
" \"value\": \"1123.625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1724952263732,\n",
" \"value\": \"99.58\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 5-2\": {},\n",
" \"Wilkinson 37 WS 8-6\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"932906.6875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"45.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"680.125\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 2-6\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"258167.953125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"49.92\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 32 WS 3-10B\": {},\n",
" \"LimeQuest 5 WS 10-10\": {\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"55.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"98.92\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 2 WS 2-9\": {},\n",
" \"LimeQuest 5 WS 9-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"14604.6796875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.001953125\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"100.1\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 6-2\": {},\n",
" \"Wilkinson 33 WS 10-3A\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1108298.625\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"43.64\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"826.625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"29.12\"\n",
" }\n",
" ]\n",
" },\n",
" \"LimeQuest 5 WS 7-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1431197.375\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1246.875\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"100.1\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 6-3\": {},\n",
" \"Wilkinson 37 WS 5-7\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1330518.25\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"35.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 34 WS 5-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1730844178737,\n",
" \"value\": \"8947.57324219\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1730844208893,\n",
" \"value\": \"42.39\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1730844179703,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1730844204775,\n",
" \"value\": \"0.13\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 10-9\": {\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724951278351,\n",
" \"value\": \"50.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1724951274299,\n",
" \"value\": \"99.05\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 1-10\": {},\n",
" \"Wilkinson 39 WS 1-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1730904600000,\n",
" \"value\": \"1450172.0\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1730904600000,\n",
" \"value\": \"41.53\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1730904600000,\n",
" \"value\": \"1439.125\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1730904600000,\n",
" \"value\": \"48.37\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 32 WS 3-10C\": {},\n",
" \"Wilkinson 33 WS 6-7\": {},\n",
" \"LimeQuest 5 WS 4-7\": {\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"99.75\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 2-8\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1968624.875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"914.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 3-6\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"971738.0\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"35.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 4 WS 1-10\": {},\n",
" \"Wilkinson 39 WS 1-7\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1640647.125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"42.04\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"694.75\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"22.45\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 3-5\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"109107.34375\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 1-5\": {},\n",
" \"Free 40 WS 1-4\": {},\n",
" \"Wilkinson 34 WS 2-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"842701.875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1107.25\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 40 WS 1-6\": {},\n",
" \"Wilkinson 39 WS 1-5\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1724951103908,\n",
" \"value\": \"1288489.5\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1724951133974,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1724951104923,\n",
" \"value\": \"249.75\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1724951129966,\n",
" \"value\": \"99.94\"\n",
" }\n",
" ]\n",
" },\n",
" \"LimeQuest 5 WS 10-9\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1731888000000,\n",
" \"value\": \"2316652.25\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1731888000000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1731888000000,\n",
" \"value\": \"1531.25\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1731888000000,\n",
" \"value\": \"100.1\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 8-8\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1749536.25\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"26.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 40 WS 5-6\": {},\n",
" \"Wilkinson 37 WS 4-7\": {},\n",
" \"Wilkinson 39 WS 1-2\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1505993.875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"38.37\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 10-1A\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1187268.375\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"213.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"LimeQuest 5 WS 8-9\": {\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"21.85\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 1-4\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1772967.75\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"916.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"46.23\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 32 WS 3-10A\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1731915000000,\n",
" \"value\": \"872721.125\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1731915000000,\n",
" \"value\": \"1140.375\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1731009000000,\n",
" \"value\": \"94.61\"\n",
" }\n",
" ]\n",
" },\n",
" \"Free 40 SR 2-1\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1731915000000,\n",
" \"value\": \"1316227.625\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1731915000000,\n",
" \"value\": \"1406.25\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1731055800000,\n",
" \"value\": \"81.59\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 37 WS 1-9B\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1945375.125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"3216.875\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"42.01\"\n",
" }\n",
" ]\n",
" },\n",
" \"Horton 34 WS 10-5\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"929216.25\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 33 WS 10-1B\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1135275.125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"40.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"47.125\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.97\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 2-10\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1319822.5\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"862.875\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"59.27\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 34 WS 10-10\": {},\n",
" \"Wilkinson 34 WS 1-8\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"470216.75\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"55.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"927.40625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"64.82\"\n",
" }\n",
" ]\n",
" },\n",
" \"LimeQuest 5 WS 7-5\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1216817.625\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1211.25\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"100.1\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 1 WS 1-9\": {},\n",
" \"Wilkinson 33 WS 4-1\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1731916200000,\n",
" \"value\": \"211459.53125\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1731916200000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1731916200000,\n",
" \"value\": \"943.15625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1731916200000,\n",
" \"value\": \"100.1\"\n",
" }\n",
" ]\n",
" },\n",
" \"Wilkinson 39 WS 2-2\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1211448.25\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"0.0\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"4.82\"\n",
" }\n",
" ]\n",
" },\n",
" \"LimeQuest 5 WS 3-5\": {\n",
" \"Totalizer 1\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"1900260.875\"\n",
" }\n",
" ],\n",
" \"Avg. Frequency 30 Days\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"60.0\"\n",
" }\n",
" ],\n",
" \"Yesterday's Volume\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"3262.625\"\n",
" }\n",
" ],\n",
" \"Run Time 30 Days %\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"45.35\"\n",
" }\n",
" ]\n",
" }\n",
" },\n",
" \"cqwatertanks\": {\n",
" \"Office Water Management\": {\n",
" \"Flow Meter 1 Flow Rate\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"119.6\"\n",
" }\n",
" ],\n",
" \"Tank 2 Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"10.46\"\n",
" }\n",
" ],\n",
" \"Tank 1 Level\": [\n",
" {\n",
" \"ts\": 1732127400000,\n",
" \"value\": \"10.47\"\n",
" }\n",
" ]\n",
" }\n",
" }\n",
" }\n",
" },\n",
" \"Henry-Petroleum-Daily-Report\": {\n",
" \"Henry-Petroleum\": {\n",
" \"abbflow\": {\n",
" \"Davis Check Meter\": {\n",
" \"Accumulated Volume\": [\n",
" {\n",
" \"ts\": 1732126800000,\n",
" \"value\": \"367614.75\"\n",
" }\n",
" ]\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n"
]
}
],
"source": [
"print(json.dumps(reportData, indent=4))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\n",
" \"OxyRock-Daily-Report\": [\n",
" \"nmelone@henry-pump.com\"\n",
" ],\n",
" \"Henry-Petroleum-Daily-Report\": [\n",
" \"nmelone@henry-pump.com\"\n",
" ]\n",
"}\n"
]
}
],
"source": [
"print(json.dumps(reportToList, indent=4))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Create an AWS SES client\n",
"ses_client = boto3.client('ses', region_name='us-east-1')\n",
"s3 = boto3.resource('s3')\n",
"BUCKET_NAME = \"thingsboard-email-reports\""
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
" # Create a workbook for each report\n",
"for report_name, report_data in reportDataSorted.items():\n",
" #will generate an email lower down\n",
" spreadsheets = []\n",
" # Create a worksheet for each company\n",
" for company_name, company_data in report_data.items():\n",
" workbook = xlsxwriter.Workbook(f\"/Users/nico/Documents/test/{report_name}-{company_name}-{dt.today().strftime('%Y-%m-%d')}.xlsx\",{'strings_to_numbers': True})\n",
" bold = workbook.add_format({'bold': True})\n",
" # Create a sheet for each device type\n",
" for device_type, device_data in company_data.items():\n",
" worksheet = workbook.add_worksheet(device_type)\n",
" \n",
" # Set the header column with device types\n",
" device_names = list(device_data.keys())\n",
" worksheet.write_column(1, 0, device_names,bold)\n",
" #TODO Fix header row and ensure data is put in correct column\n",
" # Write the data to the sheet\n",
" for i, (telemetry_name, telemetry_data) in enumerate(device_data.items()):\n",
" # Set the header row with telemetry names\n",
" telemetry_names = list(telemetry_data.keys())\n",
" worksheet.write_row(0, 1, telemetry_names, bold)\n",
" for j, (data_name, data) in enumerate(telemetry_data.items()):\n",
" values = [d[\"value\"] for d in data]\n",
" worksheet.write_row(i + 1, j+ 1, values)\n",
" worksheet.autofit()\n",
" workbook.close()\n",
" spreadsheets.append(workbook)\n",
" \n",
" \"\"\"# Store the generated report in S3.\n",
" s3.Object(BUCKET_NAME, f'{report_name}-{company_name}-{dt.today().strftime('%Y-%m-%d')}.xlsx').put(Body=open(f\"/Users/nico/Documents/test/{report_name}-{company_name}-{dt.today().strftime('%Y-%m-%d')}.xlsx\", 'rb'))\n",
" # Create an email message\n",
" msg = MIMEMultipart()\n",
" msg['Subject'] = report_name\n",
" msg['From'] = 'alerts@henry-pump.com'\n",
" msg['To'] = \", \".join(reportToList[report_name])\n",
"\n",
" # Add a text body to the message (optional)\n",
" body_text = 'Please find the attached spreadsheets.'\n",
" msg.attach(MIMEText(body_text, 'plain'))\n",
"\n",
" # Attach each workbook in the spreadsheets array\n",
" for spreadsheet in spreadsheets:\n",
" # Attach the file to the email message\n",
" attachment = MIMEBase('application', 'octet-stream')\n",
" attachment.set_payload(open(spreadsheet.filename, \"rb\").read())\n",
" encoders.encode_base64(attachment)\n",
" attachment.add_header('Content-Disposition', 'attachment', filename=spreadsheet.filename[5:])\n",
"\n",
" msg.attach(attachment)\n",
" # Send the email using AWS SES\n",
" response = ses_client.send_raw_email(\n",
" \n",
" RawMessage={'Data': msg.as_string()}\n",
" )\n",
"\n",
" print(response)\n",
" print(spreadsheets)\n",
" \"\"\""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "tbreport",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}