Skip to content

Commit

Permalink
Merge pull request #12 from JSegrave-IBM/ul-get-status
Browse files Browse the repository at this point in the history
Ul get status
  • Loading branch information
Upkar Lidder authored Oct 22, 2020
2 parents c0e71ff + 12c28ff commit c733c6e
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 110 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
__pycache__
python3
.env
.vscode
.settings
.vscode/*
9 changes: 6 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ FROM python:3.7.7-slim

ENV PYTHONUNBUFFERED=1

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY src/* /opt/microservices/
COPY requirements.txt /opt/microservices/
RUN pip install --upgrade pip \
&& pip install --upgrade pipenv\
&& apt-get update \
&& apt install -y build-essential \
&& apt install -y libmariadb3 libmariadb-dev \
&& pip install --upgrade -r /opt/microservices/requirements.txt

EXPOSE 8080
WORKDIR /opt/microservices/
Expand Down
8 changes: 5 additions & 3 deletions chart/rulesdecision/templates/istio-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: prometeo-rulesdecision
name: prometeo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
Expand All @@ -18,7 +18,7 @@ spec:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: prometeo
name: prometeo-rulesdecision
spec:
hosts:
- "*"
Expand All @@ -27,7 +27,7 @@ spec:
http:
- match:
- uri:
exact: /decision
exact: /rulesdecision
rewrite:
uri: /
route:
Expand All @@ -38,6 +38,8 @@ spec:
- match:
- uri:
prefix: /coreDecision
- uri:
prefix: /get_status
- uri:
prefix: /swaggerui
- uri:
Expand Down
14 changes: 0 additions & 14 deletions chart/rulesdecision/templates/virutalservices.yaml

This file was deleted.

3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ pandas==1.1.1
sqlalchemy==1.3.19
pymysql==0.9.2
python-dotenv
APScheduler==3.6.3
APScheduler==3.6.3
mariadb
38 changes: 0 additions & 38 deletions src/coreDecision.py

This file was deleted.

105 changes: 73 additions & 32 deletions src/core_decision_flask_app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from flask import Flask, Response, jsonify
from flask import Flask, Response, jsonify, abort
from flask_restplus import Api, Resource, fields, reqparse
from flask_cors import CORS, cross_origin
import pandas as pd
Expand All @@ -9,6 +9,9 @@
import atexit
from apscheduler.schedulers.background import BackgroundScheduler
import logging
import sqlalchemy
import sys
from flask import request

logger = logging.getLogger('core_decision_flask_app')
logger.debug('creating an instance of devices')
Expand All @@ -22,56 +25,94 @@

print('starting application')

api_prometeo_analytics = Api(app, version='1.0', title="Calculates Time-Weighted Average exposures and exposure-limit status 'gauges' for all firefighters for the last minute.", validate=False)
ns = api_prometeo_analytics.namespace('GasExposureAnalytics', 'Calculates core Prometeo analytics')

# The API does not require any input data. Once called, it will retrieve the latest data from the database.
model_input = api_prometeo_analytics.model('Enter the data:', {'todo': fields.String(description='todo')})

# On Bluemix, get the port number from the environment variable PORT
# When running this app on the local machine, default to 8080
port = int(os.getenv('PORT', 8080))

# DB Connections and identifier constants
SQLALCHEMY_DATABASE_URI = ("mysql+pymysql://"+os.getenv('MARIADB_USERNAME')
+":"+os.getenv("MARIADB_PASSWORD")
+"@"+os.getenv("MARIADB_HOST")
+":"+str(os.getenv("MARIADB_PORT"))
+"/prometeo")
DB_ENGINE = sqlalchemy.MetaData(SQLALCHEMY_DATABASE_URI).bind
ANALYTICS_TABLE = 'firefighter_status_analytics'
FIREFIGHTER_ID_COL = 'firefighter_id'
TIMESTAMP_COL = 'timestamp_mins'
STATUS_LED_COL = 'analytics_status_LED'

# We initialize the prometeo Analytics engine.
perMinuteAnalytics = GasExposureAnalytics()



# Calculates Time-Weighted Average exposures and exposure-limit status 'gauges' for all firefighters for the last minute.
def callGasExposureAnalytics():
print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))
# print(time.strftime("%A, %d. %B %Y %I:%M:%S %p"))
app.logger.info('info - running analytics')
app.logger.debug('debug - running analytics')
# call the method on the class
perMinuteAnalytics.run_analytics()

# Run all of the core analytics for Prometeo for a given minute.
status_updates_df = perMinuteAnalytics.run_analytics()

# # TODO: Pass all status details and gauges on to the dashboard via an update API
# status_updates_json = None # Information available for the current minute (may be None)
# if status_updates_df is not None:
# status_updates_json = (status_updates_df.reset_index(TIMESTAMP_COL) # index json by firefighter only
# .to_json(orient='index', date_format='iso')) # send json to dashboard
#
# resp = requests.post(API_URL, json=status_updates_json)
# if resp.status_code != EXPECTED_RESPONSE_CODE:
# app.logger.debug(f'ERROR: dashboard update API error code [{resp.status_code}]')
# app.logger.debug(f'\t with JSON: {status_updates_json}')


# Start up a scheduled job to run once per minute
ANALYTICS_FREQUENCY_SECONDS = 60
scheduler = BackgroundScheduler()
scheduler.add_job(func=callGasExposureAnalytics, trigger="interval", seconds=3)
scheduler.add_job(func=callGasExposureAnalytics, trigger="interval", seconds=ANALYTICS_FREQUENCY_SECONDS)
scheduler.start()

# Shut down the scheduler when exiting the app
atexit.register(lambda: scheduler.shutdown())


# The ENDPOINT
@ns.route('/prometeo_analytics')

class prometeo_analytics(Resource):
@api_prometeo_analytics.response(200, "Success", model_input)
@api_prometeo_analytics.expect(model_input)
def post(self):
# We prepare the arguments
parser = reqparse.RequestParser()
parser.add_argument('firefighter_ids', type=list)
args = parser.parse_args()
# The ENDPOINTS
@app.route('/get_status', methods=['GET'])
def getStatus():

try:
firefighter_id = request.args.get(FIREFIGHTER_ID_COL)
timestamp_mins = request.args.get(TIMESTAMP_COL)

# Return 404 (Not Found) if the record IDs are invalid
if (firefighter_id is None) or (timestamp_mins is None):
app.logger.error('Missing parameters : '+FIREFIGHTER_ID_COL+' : '+str(firefighter_id)
+', '+TIMESTAMP_COL+' : '+str(timestamp_mins))
abort(404)

# Read the requested Firefighter status
sql = ('SELECT '+FIREFIGHTER_ID_COL+', '+TIMESTAMP_COL+', '+STATUS_LED_COL+' FROM '+ANALYTICS_TABLE+
' WHERE '+FIREFIGHTER_ID_COL+' = '+firefighter_id+' AND '+TIMESTAMP_COL+' = "'+timestamp_mins+'"')
firefighter_status_df = pd.read_sql_query(sql, DB_ENGINE)

# Return 404 (Not Found) if no record is found
if (firefighter_status_df is None) or (firefighter_status_df.empty):
app.logger.error('No status found for : ' + FIREFIGHTER_ID_COL + ' : ' + str(firefighter_id)
+ ', ' + TIMESTAMP_COL + ' : ' + str(timestamp_mins))
abort(404)
else:
firefighter_status_json = (firefighter_status_df
.rename(columns={STATUS_LED_COL: "status"}) # name as expected by client
.iloc[0,:] # convert dataframe to series (should never be more than 1 record)
.to_json(date_format='iso'))
return firefighter_status_json

# Run all of the core analytics for Prometeo for a given minute.
limits_and_gauges_for_all_firefighters_df = perMinuteAnalytics.run_analytics()
except Exception as e:
# Return 500 (Internal Server Error) if there's any unexpected errors.
app.logger.error(f'Internal Server Error: {e}')
abort(500)

# Return the limits and status gauges as json
if limits_and_gauges_for_all_firefighters_df is None :
return None

return limits_and_gauges_for_all_firefighters_df.to_json(orient='index')



if __name__ == '__main__':
app.run(host='0.0.0.0', port=port, debug=False) # deploy with debug=False
app.run(host='0.0.0.0', port=8080, debug=False) # deploy with debug=False
12 changes: 0 additions & 12 deletions src/parameters.json

This file was deleted.

10 changes: 5 additions & 5 deletions src/prometeo_config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"windows_and_limits":
[
{ "label": "10min", "mins": 10, "gas_limits": { "carbon_monoxide": 420, "nitrogen_dioxide": 5.0, "formaldehyde": 14, "acrolein": 0.44 }},
{ "label": "30min", "mins": 30, "gas_limits": { "carbon_monoxide": 150, "nitrogen_dioxide": 1.0, "formaldehyde": 14, "acrolein": 0.18 }},
{ "label": "60min", "mins": 60, "gas_limits": { "carbon_monoxide": 83, "nitrogen_dioxide": 1.0, "formaldehyde": 14, "acrolein": 0.1 }},
{ "label": "4hr", "mins": 240, "gas_limits": { "carbon_monoxide": 33, "nitrogen_dioxide": 0.5, "formaldehyde": 14, "acrolein": 0.1 }},
{ "label": "8hr", "mins": 480, "gas_limits": { "carbon_monoxide": 27, "nitrogen_dioxide": 0.5, "formaldehyde": 14, "acrolein": 0.1 }}
{ "label": "10min", "mins": 10, "gas_limits": { "carbon_monoxide": 420, "nitrogen_dioxide": 8, "formaldehyde": 14, "acrolein": 0.44 }},
{ "label": "30min", "mins": 30, "gas_limits": { "carbon_monoxide": 150, "nitrogen_dioxide": 6, "formaldehyde": 14, "acrolein": 0.18 }},
{ "label": "60min", "mins": 60, "gas_limits": { "carbon_monoxide": 83, "nitrogen_dioxide": 4, "formaldehyde": 14, "acrolein": 0.1 }},
{ "label": "4hr", "mins": 240, "gas_limits": { "carbon_monoxide": 33, "nitrogen_dioxide": 2, "formaldehyde": 14, "acrolein": 0.1 }},
{ "label": "8hr", "mins": 480, "gas_limits": { "carbon_monoxide": 27, "nitrogen_dioxide": 1, "formaldehyde": 14, "acrolein": 0.1 }}
],
"supported_gases" :["carbon_monoxide", "nitrogen_dioxide"],
"yellow_warning_percent" : 80,
Expand Down

0 comments on commit c733c6e

Please sign in to comment.