sondehub-infra/predict/lambda_function.py
2021-09-17 23:50:36 +10:00

178 lines
5.5 KiB
Python

import boto3
import botocore.credentials
from botocore.awsrequest import AWSRequest
from botocore.endpoint import URLLib3Session
from botocore.auth import SigV4Auth
import json
import os
from datetime import datetime, timedelta, timezone
import sys
import traceback
import http.client
import math
import logging
import gzip
from io import BytesIO
import base64
HOST = os.getenv("ES")
def predict(event, context):
path = "predictions-*/_search"
payload = {
"aggs": {
"2": {
"terms": {
"field": "serial.keyword",
"order": {
"_key": "desc"
},
"size": 1000
},
"aggs": {
"1": {
"top_hits": {
"_source": True,
"size": 1,
"sort": [
{
"datetime": {
"order": "desc"
}
}
]
}
}
}
}
},
"size": 0,
"stored_fields": [
"*"
],
"script_fields": {},
"docvalue_fields": [
{
"field": "datetime",
"format": "date_time"
}
],
"_source": {
"excludes": []
},
"query": {
"bool": {
"must": [],
"filter": [
{
"range": {
"datetime": {
"gte": "now-6h",
"lte": "now",
"format": "strict_date_optional_time"
}
}
}
],
"should": [
],
"must_not": []
}
}
}
if "queryStringParameters" in event:
if "vehicles" in event["queryStringParameters"] and event["queryStringParameters"]["vehicles"] != "RS_*;*chase" and event["queryStringParameters"]["vehicles"] != "":
for serial in event["queryStringParameters"]["vehicles"].split(","):
payload["query"]["bool"]["should"].append(
{
"match_phrase": {
"serial.keyword": serial
}
}
)
# for single sonde allow longer predictions
payload['query']['bool']['filter'].pop(0)
logging.debug("Start ES Request")
results = es_request(payload, path, "GET")
logging.debug("Finished ES Request")
output = []
for sonde in results['aggregations']['2']['buckets']:
data = sonde['1']['hits']['hits'][0]['_source']
output.append({
"vehicle": data["serial"],
"time": data['datetime'],
"latitude": data['position'][1],
"longitude": data['position'][0],
"altitude": data['altitude'],
"ascent_rate": data['ascent_rate'],
"descent_rate": data['descent_rate'],
"burst_altitude": data['burst_altitude'],
"descending": 1 if data['descending'] == True else 0,
"landed": 1 if data['landed'] == True else 0,
"data": json.dumps(data['data'])
})
compressed = BytesIO()
with gzip.GzipFile(fileobj=compressed, mode='w') as f:
json_response = json.dumps(output)
f.write(json_response.encode('utf-8'))
gzippedResponse = compressed.getvalue()
return {
"body": base64.b64encode(gzippedResponse).decode(),
"isBase64Encoded": True,
"statusCode": 200,
"headers": {
"Content-Encoding": "gzip",
"content-type": "application/json"
}
}
def es_request(payload, path, method):
# get aws creds
session = boto3.Session()
params = json.dumps(payload)
compressed = BytesIO()
with gzip.GzipFile(fileobj=compressed, mode='w') as f:
f.write(params.encode('utf-8'))
params = compressed.getvalue()
headers = {"Host": HOST, "Content-Type": "application/json",
"Content-Encoding": "gzip"}
request = AWSRequest(
method=method, url=f"https://{HOST}/{path}", data=params, headers=headers
)
SigV4Auth(boto3.Session().get_credentials(),
"es", "us-east-1").add_auth(request)
session = URLLib3Session()
r = session.send(request.prepare())
return json.loads(r.text)
if __name__ == "__main__":
# print(get_sondes({"queryStringParameters":{"lat":"-28.22717","lon":"153.82996","distance":"50000"}}, {}))
# mode: 6hours
# type: positions
# format: json
# max_positions: 0
# position_id: 0
# vehicles: RS_*;*chase
print(predict(
{"queryStringParameters": {
"vehicles": ""
}}, {}
))
# get list of sondes, serial, lat,lon, alt
# and current rate
# for each one, request http://predict.cusf.co.uk/api/v1/?launch_latitude=-37.8136&launch_longitude=144.9631&launch_datetime=2021-02-22T00:15:18.513413Z&launch_altitude=30000&ascent_rate=5&burst_altitude=30000.1&descent_rate=5
# have to set the burst alt slightly higher than the launch