Files
POCloud-Email-Reports/reports_s3_xlsx.py
Patrick McDonagh 7e324d4ab2 Converts all to working Lambda function within AWS.
reports_xlsx.py left in the repo for legacy implementation
2018-03-13 18:21:05 -05:00

202 lines
7.3 KiB
Python

"""Prepare and send daily reports for Advanced VFD IPP devices in Meshify."""
import meshify
import json
from datetime import datetime, timedelta
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.mime.base import MIMEBase
from time import time
from tzlocal import get_localzone
import xlsxwriter
import logging
# S3 Shiz
import boto3
# import botocore
s3 = boto3.resource('s3')
ses = boto3.client('ses')
BUCKET_NAME = "pocloud-email-reports"
EMAIL_FROM_ADDRESS = "alerts@henry-pump.com"
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def get_s3_device_types():
"""Get device types from s3 objects."""
"""Each object must have a _to.json file and a _channels.json file."""
device_types = []
report_bucket = s3.Bucket(BUCKET_NAME)
to_bucket_files = sorted(map(lambda x: x.key.split("/")[1], filter(lambda x: x.key[-1] != "/", report_bucket.objects.filter(Prefix='to_files'))))
channel_config_bucket_files = sorted(map(lambda x: x.key.split("/")[1], filter(lambda x: x.key[-1] != "/", report_bucket.objects.filter(Prefix='channel_config'))))
for i in range(0, len(to_bucket_files)):
to_part = to_bucket_files[i].split("_")[0]
config_part = channel_config_bucket_files[i].split("_")[0]
if to_part == config_part:
device_types.append(to_part)
return device_types
def read_s3_device_config(device_type):
"""Get the JSON object config for a device_type."""
obj = s3.Object(BUCKET_NAME, "channel_config/{}_channels.json".format(device_type))
return json.loads(obj.get()['Body'].read().decode('utf-8'))
def read_s3_tofiles(device_type):
"""Get the JSON object _to file for a device_type."""
obj = s3.Object(BUCKET_NAME, "to_files/{}_to.json".format(device_type))
return json.loads(obj.get()['Body'].read().decode('utf-8'))
def send_ses_email(msg):
"""Send an email using AWS SES."""
response = ses.send_raw_email(
Source=EMAIL_FROM_ADDRESS,
RawMessage={
'Data': msg.as_string()
},
FromArn='',
SourceArn='',
ReturnPathArn=''
)
return response
def join_company_info(obj_with_companyId, company_lookup_obj):
"""Add company information to an object with companyId property."""
obj_with_companyId['company'] = company_lookup_obj[obj_with_companyId['companyId']]
return obj_with_companyId
def filter_object_parameters(ob, list_of_parameters):
"""Return an object of just the list of paramters."""
new_ob = {}
for par in list_of_parameters:
try:
new_ob[par] = ob[par]
except KeyError:
new_ob[par] = None
return new_ob
def group_by_company(devices):
"""Group a list of devices by company."""
grouped = {}
for dev in devices:
try:
grouped[dev['company']['name']].append(dev)
except KeyError:
grouped[dev['company']['name']] = [dev]
return grouped
def prep_emails(device_type, channel_config_list, to_list):
"""Prepare a message for sending for a devicetype."""
messages = []
meshify_channelnames = [m['meshify_name'] for m in channel_config_list]
all_devicetypes = meshify.query_meshify_api("devicetypes")
this_devicetype = meshify.find_by_name(device_type, all_devicetypes)
companies = meshify.query_meshify_api("companies")
company_lookup = {}
for x in companies:
company_lookup[x['id']] = x
devices = meshify.query_meshify_api("devices")
this_devices = filter(lambda x: x['deviceTypeId'] == this_devicetype['id'], devices)
this_devices = [join_company_info(x, company_lookup) for x in this_devices]
for i in range(0, len(this_devices)):
this_devices[i]['values'] = filter_object_parameters(
meshify.query_meshify_api("devices/{}/values".format(this_devices[i]['id'])), meshify_channelnames)
this_devices = group_by_company(this_devices)
for comp in this_devices:
local_tz = get_localzone()
now_t = time()
now_dt = datetime.utcfromtimestamp(now_t)
now = local_tz.localize(now_dt)
filename_datestring = datetime.now().strftime("%Y%m%d")
workbook = xlsxwriter.Workbook("/tmp/{}_{}_{}.xlsx".format(device_type, comp, filename_datestring))
worksheet = workbook.add_worksheet()
worksheet.set_column('A:A', 20)
bold = workbook.add_format({'bold': True})
red = workbook.add_format({'font_color': 'red'})
worksheet.write(0, 0, "Well Name", bold)
for i in range(0, len(channel_config_list)):
worksheet.write(0, i+1, channel_config_list[i]['vanity_name'], bold)
sorted_company_devices = sorted(this_devices[comp], key=lambda x: x['vanityName'])
for j in range(0, len(sorted_company_devices)):
dev = sorted_company_devices[j]
worksheet.write(j+1, 0, dev['vanityName'])
for k in range(0, len(meshify_channelnames)):
v = meshify_channelnames[k]
dt_ts = datetime.utcfromtimestamp(dev['values'][v]['timestamp'])
dt_loc = local_tz.localize(dt_ts)
stale = (now - dt_loc) > timedelta(hours=24)
try:
v = round(float(dev['values'][v]['value']), 3)
if stale:
worksheet.write_number(j+1, 1+k, v, red)
else:
worksheet.write_number(j+1, 1+k, v)
except ValueError:
v = str(dev['values'][v]['value'])
if stale:
worksheet.write(j+1, 1+k, v, red)
else:
worksheet.write(j+1, 1+k, v)
workbook.close()
s3.Object(BUCKET_NAME, 'created_reports/{}_{}_{}.xlsx'.format(device_type, comp, filename_datestring)).put(Body=open('/tmp/{}_{}_{}.xlsx'.format(device_type, comp, filename_datestring), 'rb'))
try:
email_to = to_list[comp]
except KeyError:
logger.error("No recipients for that company({})!".format(comp))
continue
attachment = MIMEBase('application', 'octet-stream')
attachment.set_payload(open("/tmp/{}_{}_{}.xlsx".format(device_type, comp, filename_datestring), "rb").read())
encoders.encode_base64(attachment)
now = datetime.now()
datestr = now.strftime("%a %b %d, %Y")
msg = MIMEMultipart('alternative')
msg['Subject'] = "{} Daily {} Report for {}".format(comp, device_type.upper(), datestr)
msg['From'] = "alerts@henry-pump.com"
msg['To'] = ", ".join(email_to)
filename = "{} {}.xlsx".format(comp, datestr)
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(attachment)
messages.append(msg)
return messages
def lambda_handler(event, context):
"""Handle the lambda function call."""
device_type_list = get_s3_device_types()
to_lists = list(map(lambda x: read_s3_tofiles(x), device_type_list))
channel_configs = list(map(lambda x: read_s3_device_config(x), device_type_list))
for i in range(0, len(device_type_list)):
emails = prep_emails(device_type_list[i], channel_configs[i], to_lists[i])
for email in emails:
send_ses_email(email)
logger.info("Sent email for {} to {}".format(device_type_list[i], email['To']))