def __basicAuthentication(): """This is a private helper method used by the http_basic_authenticate. """ auth = request.authorization logging.debug("Authenticating HTTP Basic Authentication " "using Authorization [{0}]" .format(auth)) valid_username = ini_config.get("Sensor", "SENSOR_REST_API_USERNAME") valid_password = ini_config.get("Sensor", "SENSOR_REST_API_PASSWORD") if not auth: logging.debug("HTTP Basic Authentication header not found.") return False elif (auth.username != valid_username): logging.debug("user [{0}] is not valid. Authentication failed" .format(auth.username)) return False elif (auth.password != valid_password): logging.debug("Password not valid. user [{0}] failed authentication." .format(auth.username)) return False logging.debug("user [{0}] has been authenticated." .format(auth.username)) return True
def subscribe_temperature(): """ Subscribe to temperature sensor data. Parameters ---------- Returns ------- """ # The callback for when the client receives a CONNACK response from # the server. def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) topic = ini_config.get("MQTT", "MQTT_TOPIC") # Subscribing in on_connect() means that if we lose the connection # and reconnect then subscriptions will be renewed. mqttc.subscribe(topic, qos=0) # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) mqtt_id = ini_config.get("MQTT", "MQTT_CLIENT_ID") user = ini_config.get("MQTT", "MQTT_USERNAME") pw = ini_config.get("MQTT", "MQTT_PASSWORD") host = ini_config.get("MQTT", "MQTT_HOST") port = ini_config.getint("MQTT", "MQTT_PORT") mqttc = mqtt.Client(client_id=mqtt_id, clean_session=True, protocol=mqtt.MQTTv31) mqttc.on_connect = on_connect mqttc.on_message = on_message mqttc.username_pw_set(user, password=pw) logging.debug("Connecting to MQTT Broker: " "host [{0}], port [{1}], user [{2}]" .format(host, port, user)) mqttc.connect(host, port) # Blocking call that processes network traffic, dispatches callbacks # and handles reconnecting. # Other loop*() functions are available that give a threaded interface # and a manual interface. mqttc.loop_forever() return
def del_readings(serial): """ Deletes all measurement data for the given serial Parameters ---------- serial: str (required) sensor unique serial number Returns ------- nothing. """ logging.debug("Deleting all measurements in SQLite database for " "serial [{0}]".format(serial)) sql_db = ini_config.get("SqlLite", "SQLITE_DB") conn = sqlite3.connect(sql_db) logging.debug("Connected to SQLite DB [{0}]".format(sql_db)) c = conn.cursor() c.execute("DELETE FROM readings WHERE serial = '{0}' " .format(serial)) conn.commit() logging.debug("Measurements have been deleted from SQLite database") conn.close() logging.debug("Disconnected from SQLite DB [{0}]".format(sql_db)) return
def read_publish_sensor_data(): """ Function used to read sensor data and publish the readings to a topic served by an MQTT server. """ # MQTT client publisher mqtt_publisher = MQTTPublisher() sensor_serial = ini_config.get("Sensor", "SENSOR_TEMPERATURE_SERIAL") sleep_timeout = ini_config.getint("Sensor", "SENSOR_SLEEP_TIME") # start daemon forever loop while True: try: # read and publish sensor reading to topic in MQTT server logging.debug("publishing sensor serial [{0}] data".format(sensor_serial)) mqtt_publisher.publish_temperature(sensor_serial) except (Exception) as err: sys.stderr.write(str(err)) logging.exception("Error reading/publishing sensor data. [{0}]".format(err)) except: # catch *all* other exceptions err = sys.exc_info()[0] logging.exception("Error occurred in mqtt daemon: [{0}]".format(err)) write_to_file("<p>Error in mqttpublisher daemon: [{0}]</p>".format(err), sys.stderr) time.sleep(sleep_timeout) return
def del_sensor(serial): """ Deletes sensor data for the given serial Parameters ---------- serial: str (required) sensor unique serial number Returns ------- nothing. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["sensors"] logging.debug("Deleting sensor with serial [{0}] from MongoDB DB.".format(serial)) result = coll.delete_many({"serial": serial}) logging.debug("[{0}] sensors have been deleted from MongoDB database".format(result.deleted_count)) db.client.close() logging.debug("Disconnected from MongoDB") return
def del_readings(serial): """ Deletes all measurement data for the given serial Parameters ---------- serial: str (required) sensor unique serial number Returns ------- nothing. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["readings"] logging.debug( "Deleting all readings in the MongoDB collection [{0}] " "for sensor serial [{1}].".format(coll, serial) ) result = coll.delete_many({"serial": serial}) logging.debug("[{0}] sensor readings have been deleted from " "MongoDB database".format(result.deleted_count)) db.client.close() logging.debug("Disconnected from MongoDB") return
def add_sensor(serial, geolocation, location, address, state, name, sensor_type, description): """ Adds given sensor data to sensor database Parameters ---------- serial: str (required) sensor unique serial number. geolocation: str (optional) GEO Location: LATITUDE, LONGITUDE location: str (optional) ENGINE, HOME, PATIO, ... address: str (optional) Address where sensor is located state: str (required) UP, DOWN, ... name: str (required) name to help identify this sensor sensor_type: str (required) HUMIDITY, PRESSURE, TEMPERATURE, VELOCITY, ... description: str(optional) helps describe this sensor Returns ------- nothing. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["sensors"] logging.debug( "Adding following sensor to MongoDB database: " "serial [{0}], state [{1}], name [{2}], type [{3}]".format(serial, state, name, sensor_type) ) result = coll.insert_one( { "_id": serial, "serial": serial, "geolocation": geolocation, "location": location, "address": address, "state": state, "name": name, "type": sensor_type, "description": description, } ) logging.debug("Sensor with id [{0}] has been inserted " "into MongoDB database".format(result.inserted_id)) db.client.close() logging.debug("Disconnected from MongoDB") return
def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) topic = ini_config.get("MQTT", "MQTT_TOPIC") # Subscribing in on_connect() means that if we lose the connection # and reconnect then subscriptions will be renewed. mqttc.subscribe(topic, qos=0)
def teardown_request(exception): sql_enabled = ini_config.getboolean("SqlLite", "SQLITE_DB_ENABLE") sql_db = ini_config.get("SqlLite", "SQLITE_DB") # disconnect DB connection only if DB is enabled if sql_enabled and hasattr(g, 'db'): g.db.close() logging.debug("Disconnected from DB [{0}]".format(sql_db)) return
def add_sensor(serial, geolocation, location, address, state, name, sensor_type, description): """ Adds given sensor data to sensor database Parameters ---------- serial: str (required) sensor unique serial number. geolocation: str (optional) GEO Location: LATITUDE, LONGITUDE location: str (optional) ENGINE, HOME, PATIO, ... address: str (optional) Address where sensor is located state: str (required) UP, DOWN, ... name: str (required) name to help identify this sensor sensor_type: str (required) HUMIDITY, PRESSURE, TEMPERATURE, VELOCITY, ... description: str(optional) helps describe this sensor Returns ------- nothing. """ logging.debug("Inserting sensor in SQLite database: " "serial [{0}], state [{1}], name [{2}], type [{3}]" .format(serial, state, name, sensor_type)) sql_db = ini_config.get("SqlLite", "SQLITE_DB") conn = sqlite3.connect(sql_db) logging.debug("Connected to SQLite DB [{0}]".format(sql_db)) c = conn.cursor() c.execute("INSERT INTO sensor ( serial, geolocation, location, " " address, state, name, type, description ) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", (serial, geolocation, location, address, state, name, sensor_type, description)) conn.commit() logging.debug("sensor has been committed in database") conn.close() logging.debug("Disconnected from SQLite DB [{0}]".format(sql_db)) return
def get_readings(serial, current_datetime, past_datetime): """ Returns ..... Parameters ---------- serial: str (required) sensor unique serial number current_datetime: str (required) a valid UTC timestamp past_datetime: str (required) a valid UTC timestamp Returns ------- dict: A sensor dictionary containing column names as keys, and corresponding values. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["readings"] logging.debug( "Retrieving readings for sensor with serial [{0}] " "between [{1}] and [{2}] from MongoDB database.".format(serial, past_datetime, current_datetime) ) cursor = coll.find({"serial": serial, "utc": {"$lt": current_datetime}, "utc": {"$gt": past_datetime}}).sort( "utc", pymongo.ASCENDING ) data = None if cursor.count() > 0: data = list(cursor) logging.debug("Readings [{0}] retrieved from MongoDB for sensor with " "serial [{1}]".format(data, serial)) db.client.close() logging.debug("Disconnected from MongoDB") if data is not None: # convert any MongoDB ObjectId and others (ie Binary, Code, etc) # to a string equivalent such as "$oid." and revert back to dict. data = json.loads(json_util.dumps(data)) return data
def setup_routes(): """Sets up the routes for the REST resources """ # The Flask RESTful API object api = FlaskRESTfulAPI(current_app) # rest_apis: REST APIs that should be enabled. restful_apis = ini_config.get("REST", "RESTFUL_APIS") rest_api_list = restful_apis.upper().split(",") rest_apis = [str(value).strip() for value in rest_api_list] # Temperature API if "TEMPERATURE" in rest_apis: api.add_resource(RESTTemperatureResource, "/temperature/<string:to_unit>") logging.info("temperature REST API is enabled") # Weight API if "WEIGHT" in rest_apis: api.add_resource(RESTWeightResource, "/weight/<string:to_unit>") logging.info("weight REST API is enabled") # Length API if "LENGTH" in rest_apis: api.add_resource(RESTLengthResource, "/length/<string:to_unit>") logging.info("length REST API is enabled") # PRODUCT_INFO if "PRODUCT_INFO" in rest_apis: api.add_resource(RESTProductInfoResource, "/information/product") logging.info("Product Info REST API is enabled") # IoT - Sensor Temperature API if "SENSOR_TEMPERATURE" in rest_apis: api.add_resource(RESTSensorTemperatureResource, "/temperature/sensors/<string:serial>") logging.info("Sensor Temperature REST API is enabled") # IoT - Sensor Information API if "SENSOR_INFO" in rest_apis: api.add_resource(RESTSensorInfoResource, "/information/sensors", "/information/sensors/<string:serial>") logging.info("Sensor Information REST API is enabled") # IoT - Sensor Temperature Analytics API if "SENSOR_TEMPERATURE_ANALYTICS" in rest_apis: api.add_resource(RESTSensorTemperatureAnalyticsResource, "/analytics/temperature/sensors/<string:serial>") logging.info("Sensor Temperature Analytics REST API is enabled") # URL API if "URL" in rest_apis: api.add_resource(RESTUrlResource, "/resource") logging.info("URL REST API is enabled")
def get_sensor(serial): """ Returns a tuple corresponding to the sensor table in the database for the given sensor serial. Parameters ---------- serial: str (required) sensor unique serial number Returns ------- dict: A sensor dictionary containing column names as keys, and corresponding values. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["sensors"] logging.debug("Retrieving sensor with serial [{0}] " "from MongoDB database.".format(serial)) cursor = coll.find({"serial": serial}) # at most we are only allowed to have one sensor per serial if cursor.count() > 1: db.client.close() raise RuntimeError( "More than one sensor found in MongoDB [{0}] " "for sensor serial [{1}]".format(db, serial) ) data = None for document in cursor: data = document logging.debug("[{0}] sensors have been retrieved from MongoDB DB".format(data)) db.client.close() logging.debug("Disconnected from MongoDB") if data is not None: # convert any MongoDB ObjectId and others (ie Binary, Code, etc) # to a string equivalent such as "$oid." and revert back to dict. data = json.loads(json_util.dumps(data)) return data
def get_readings(serial, current_datetime, past_datetime): """ Returns ..... Parameters ---------- serial: str (required) sensor unique serial number current_datetime: str (required) a valid UTC timestamp past_datetime: str (required) a valid UTC timestamp Returns ------- dict: A sensor dictionary containing column names as keys, and corresponding values. """ logging.debug("Retrieving readings from sensor with serial [{0}] " "between [{1}] and [{2}] from SQLite database." .format(serial, past_datetime, current_datetime)) sql = ("SELECT utc, serial, unit, value FROM readings WHERE serial = '{0}' " "AND utc BETWEEN '{1}' AND '{2}' " "ORDER BY utc ASC" .format(serial, past_datetime, current_datetime)) sql_db = ini_config.get("SqlLite", "SQLITE_DB") conn = sqlite3.connect(sql_db) logging.debug("Connected to SQLite DB [{0}]".format(sql_db)) c = conn.cursor() c.row_factory = dict_factory cursor = c.execute(sql) data = cursor.fetchall() conn.commit() conn.close() logging.debug("Disconnected from SQLite DB [{0}]".format(sql_db)) return data
def add_reading(unit, value, utc, serial): """ Adds given measurement data to sensor database Parameters ---------- unit: str (required) degF, degC, degF. value: float (required) a float number utc: str (required) UTC timestamp of the reading serial: str (required) sensor unique serial number Returns ------- nothing. """ mongodb_name = ini_config.get("MongoDB", "MONGO_DB") db = MongoDB.database(mongodb_name) coll = db["readings"] result = coll.insert_one({"unit": unit, "value": value, "utc": utc, "serial": serial}) logging.debug( "Sensor reading with id [{0}] has been inserted " "into MongoDB database".format(result.inserted_id) ) db.client.close() logging.debug("Disconnected from MongoDB") return
def get_sensor(serial): """ Returns a tuble corresponding to the sensor table in the database for the given sensor serial. Parameters ---------- serial: str (required) sensor unique serial number Returns ------- dict: A sensor dictionary containing column names as keys, and corresponding values. """ logging.debug("Retrieving sensor with serial [{0}] from database." .format(serial)) sql_db = ini_config.get("SqlLite", "SQLITE_DB") conn = sqlite3.connect(sql_db) logging.debug("Connected to SQLite DB [{0}]".format(sql_db)) c = conn.cursor() c.row_factory = dict_factory cursor = c.execute(("SELECT * FROM sensor WHERE serial = '{0}'" .format(serial))) data = cursor.fetchone() conn.commit() conn.close() logging.debug("Disconnected from SQLite DB [{0}]".format(sql_db)) return data
def add_reading(unit, value, utc, serial): """ Adds given measurement data to sensor database Parameters ---------- unit: str (required) degF, degC, degF. value: float (required) a float number utc: str (required) UTC timestamp of the reading serial: str (required) sensor unique serial number Returns ------- nothing. """ sql_db = ini_config.get("SqlLite", "SQLITE_DB") conn = sqlite3.connect(sql_db) logging.debug("Connected to SQLite DB [{0}]".format(sql_db)) c = conn.cursor() c.execute("INSERT INTO readings (id, unit, value, utc, serial) " "VALUES (?,?,?,?,?)", (None, unit, value, utc, serial)) conn.commit() logging.debug("Measurement has been committed in SQLite database") conn.close() logging.debug("Disconnected from SQLite DB [{0}]".format(sql_db)) return
import logging from flask import Flask from rgapps.config import ini_config from rgapps.http.routes import setup_routes __author__ = "Rubens S. Gomes <*****@*****.**>" __copyright__ = "Copyright (c) 2015 Rubens S. Gomes" __license__ = "All Rights Reserved" __maintainer__ = "Rubens Gomes" __email__ = "*****@*****.**" __status__ = "Experimental" instance_path = ini_config.get("Flask", "INSTANCE_PATH") logging.info("creating Flask app ...") app = Flask(__name__, instance_path=instance_path, instance_relative_config=True) is_debug = ini_config.getboolean("Flask", "DEBUG") is_testing = ini_config.getboolean("Flask", "TESTING") is_json_sort_keys = ini_config.getboolean("Flask", "JSON_SORT_KEYS") max_content_length = ini_config.getint("Flask", "MAX_CONTENT_LENGTH") app.config.update(DEBUG=is_debug, TESTING=is_testing, JSON_SORT_KEYS=is_json_sort_keys, MAX_CONTENT_LENGTH=max_content_length)
def publish_temperature(serial): """ Publishes the given temperature sensor data to MQTT message broker. Parameters ---------- serial: str (required) sensor serial number Returns ------- """ # test serial if is_blank(serial): raise IllegalArgumentException("serial is required") mqtt_id = ini_config.get("MQTT", "MQTT_CLIENT_ID") user = ini_config.get("MQTT", "MQTT_USERNAME") pw = ini_config.get("MQTT", "MQTT_PASSWORD") host = ini_config.get("MQTT", "MQTT_HOST") port = ini_config.getint("MQTT", "MQTT_PORT") topic = ini_config.get("MQTT", "MQTT_TOPIC") mqttc = mqtt.Client(client_id=mqtt_id, clean_session=True, protocol=mqtt.MQTTv31) mqttc.username_pw_set(user, password=pw) sensor_temperature = DS18B20Sensor(serial) readings = sensor_temperature.get_measurement() message = OrderedDict() message["value"] = readings.get_value() message["unit"] = readings.get_unit() message["utc"] = readings.get_utc() json_message = json.dumps(message, indent=2, sort_keys=True) auth = OrderedDict() auth["username"] = user auth["password"] = pw logging.debug("Publishing to MQTT Broker: " "host [{0}], port [{1}], client id [{2}], " "user [{3}], sensor serial [{4}]" .format(host, port, mqtt_id, user, serial)) publish.single(topic, payload=json_message, qos=0, retain=False, hostname=host, port=port, client_id=mqtt_id, keepalive=20, auth=auth) logging.debug("Message [{0}] was published correctly: " "host [{1}], port [{2}], client id [{3}], " "user [{4}], sensor serial [{5}]" .format(message, host, port, mqtt_id, user, serial)) return
def test_send_text(self): logging.debug("testing sms send_text") phone = ini_config.get("SMS", "TESTING_PHONE") SMS.send_text(phone, "TESTING message") return
def read_store_readings (): """ Function used to read and store sensor readings """ logging.debug("inside read_store_readings...") if globalFlaskApp is None: logging.error("Flask has not been initialized!") raise EnvironmentError("Flask has not been initialized") # error flag used to send email only once if error occurs. error_flag = False headers = {'content-type': 'application/json'} sensor_url = ini_config.get("Sensor", "SENSOR_TEMPERATURE_URL") sensor_serial = ini_config.get("Sensor", "SENSOR_TEMPERATURE_SERIAL") rest_url = (sensor_url + "/" + sensor_serial) logging.debug("sensor REST URL is [{0}]".format(rest_url)) rest_user = ini_config.get("Sensor", "SENSOR_REST_API_USERNAME") rest_pw = ini_config.get("Sensor", "SENSOR_REST_API_PASSWORD") req_timeout = ini_config.getint("Sensor", "SENSOR_REQUEST_TIMEOUT") sleep_timeout = ini_config.getint("Sensor", "SENSOR_SLEEP_TIME") recipient = ini_config.get("Email", "RECIPIENT_EMAIL") with globalFlaskApp.app_context(): logging.debug("starting forever loop within Flask app context") # start daemon forever loop while True: try: # collect data from sensor using RESTFul API logging.debug("Sending request to [{0}] with user [{1}]" .format(rest_url, rest_user)) r = requests.get(rest_url, verify=False, auth=(rest_user, rest_pw), headers=headers, timeout=req_timeout) # if code gets here no exception has occurred. reset flag. error_flag = False if (r.status_code != 200): logging.error("Response status code [{0}] : [{1}]" .format(r.status_code, r.text)) else: output = r.json() sensor = output[SENSOR_KEY] readings = output[DATA_KEY] logging.debug("Adding sensor record with unit [{0}], " "value [{1}], utc [{2}], serial [{3}] to " "database." .format(readings["unit"], readings["value"], readings["utc"], sensor["serial"])) SensorDAO.add_reading(readings["unit"], readings["value"], readings["utc"], sensor["serial"]) # python 3.4: ConnectionRefusedError except (ConnectionError, Timeout) as err: # e.g., server is down. sys.stderr.write(str(err)) logging.exception("Connection Error with URL [{0}], " "user [{1}] in runserver daemon: [{2}]" .format(rest_url, rest_user, err)) if not error_flag : # only send email once. subject = "sensorserver: Connection/Timeout Error" logging.info("Sending email to [{0}] with subject [{1}]" .format(recipient, subject)) message = ("Connection/Timeout Error to URL [{0}]: [{1}]" .format(rest_url, err)) try: EMail.send_email(recipient, subject, message) logging.info("email to [{0}] with subject [{1}] sent." .format(recipient, subject)) except Exception as mail_err: logging.error("Error [{0}] sending email." .format(mail_err)) error_flag = True except (HTTPError, RequestException) as err: sys.stderr.write(str(err)) logging.exception("HTTP/Request Error to URL [{0}] in " "runserver daemon: [{1}]" .format(rest_url, err)) if not error_flag : # only send email once. subject = "sensorserver: HTTP Error" logging.info("Sending email to [{0}] with subject [{1}]" .format(recipient, subject)) message = ("HTTP/Request to URL [{0}] Error: [{1}]" .format(rest_url, err)) try: EMail.send_email(recipient, subject, message) logging.info( "email to [{0}] with subject [{1}] was sent." .format(recipient, subject)) except Exception as mail_err: logging.error("Error [{0}] sending email." .format(mail_err)) error_flag = True except (EnvironmentError, Exception) as err: sys.stderr.write(str(err)) logging.exception("Error in runserver daemon: [{0}]" .format(err)) if not error_flag : # only send email once. subject = "sensorserver: Environment Error" logging.info("Sending email to [{0}] with subject [{1}]" .format(recipient, subject)) message = "EXITING APPLICATION. Error: [{0}]".format(err) try: EMail.send_email(recipient, subject, message) logging.info( "email to [{0}] with subject [{1}] was sent." .format(recipient, subject)) except Exception as mail_err: logging.error("Error [{0}] sending email." .format(mail_err)) error_flag = True except: # catch *all* other exceptions err = sys.exc_info()[0] logging.exception("Error occurred in runserver daemon: [{0}]" .format(err)) write_to_file("<p>Error in runsensor daemon: [{0}]</p>" .format(err), sys.stderr) exit(1) time.sleep(sleep_timeout) return
def run(): """ daemon run function. This function should be called to start the system. """ instance_path = ini_config.get("Flask", "INSTANCE_PATH") # app: Flask application object logging.debug("initializing the Flask app") global globalFlaskApp globalFlaskApp = Flask(__name__, instance_path=instance_path, instance_relative_config=True) is_debug = ini_config.getboolean("Flask", "DEBUG") is_testing = ini_config.getboolean("Flask", "TESTING") is_json_sort_keys = ini_config.getboolean("Flask", "JSON_SORT_KEYS") max_content_length = ini_config.getint("Flask", "MAX_CONTENT_LENGTH") globalFlaskApp.config.update(DEBUG=is_debug, TESTING=is_testing, JSON_SORT_KEYS=is_json_sort_keys, MAX_CONTENT_LENGTH=max_content_length) with globalFlaskApp.app_context(): logging.info("Starting application ...") from rgapps.utils.utility import get_log_file_handles logger_fds = get_log_file_handles(logging.getLogger()) logging.debug("Logger file handles fileno [{0}]" .format(logger_fds)) system = platform.system() if system == "Linux": logging.info("Server running on Linux.") pid_file = ini_config.get("Sensor", "SENSOR_PID_FILE") working_dir = ini_config.get("Logging", "WORKING_DIR") logging.debug("Instantiating daemon with pid_file [{0}] " "and working_dir [{1}]" .format(pid_file, working_dir)) import daemon.pidfile daemon_context = daemon.DaemonContext( working_directory=working_dir, umask=0o002, pidfile=daemon.pidfile.PIDLockFile(pid_file)) logging.debug("Setting up daemon signal map") daemon_context.signal_map = { signal.SIGTERM: program_cleanup } logging.debug("daemon signal map has been setup") if (logger_fds): logging.debug("setting files_preserve for the log file " "descriptor [{0}]" .format(logger_fds)) daemon_context.files_preserve = logger_fds logging.debug("Starting daemon by opening its context.") daemon_context.open() logging.info("Calling read_store_readings....") read_store_readings() logging.debug("Closing the daemon context.") daemon_context.close() else: logging.info("Server running on Windows system ...") read_store_readings() return
def before_request(): """ Handler to be run at the beginning of every single request to ensure that the income request is compliant to the existing REST API. For example, it checks to ensure that the ACCEPT HTTP Header contains the Content Type support by the REST API. """ url = request.url logging.debug("Requested URL [{0}]".format(url)) accept = request.headers.get('Accept') logging.debug("HTTP Request Header Accept [{0}]".format(accept)) accept_language = request.headers.get('Accept-Language') logging.debug("HTTP Request Header Accept-Language [{0}]" .format(accept_language)) content_length = request.headers.get('Content-Length') logging.debug("HTTP Request Content-Length [{0}]" .format(content_length)) ip = request.remote_addr logging.debug("Client IP Address [{0}]".format(ip)) user_agent = request.headers.get('User-Agent') logging.debug("HTTP Client User-Agent [{0}]" .format(user_agent)) date = request.headers.get("Date") logging.debug("HTTP Request date [{0}]".format(date)) json_weigth = request.accept_mimetypes["application/json"] logging.debug("application/json accept weight [{0}]" .format(json_weigth)) if json_weigth <= 0: # The incoming HTTP Accept header specifies a media type that is # not supported by this application REST API. Currently, only # the JSON media type is accepted. msg = "HTTP Request Header Accept [{0}] not supported".format(accept) logging.warn(msg) raise NotAcceptable(msg) method = request.method if method != 'GET': # At this time only 'GET' methods are accepted msg = "HTTP Method [{0}] not supported".format(accept) logging.warn(msg) raise MethodNotAllowed(msg) # acquire DB connection only if DB is enabled is_sql_enabled = ini_config.getboolean("SqlLite", "SQLITE_DB_ENABLE") sql_db = ini_config.get("SqlLite", "SQLITE_DB") if is_sql_enabled : db = getattr(g, 'db', None) if db is None: g.db = sqlite3.connect(sql_db) logging.debug("Connected to DB [{0}]".format(sql_db)) return
def send_email(recipient, subject, message): """Sends given message using Gmail credentials defined in the configuration file. Parameters ---------- recipient: str (required) recipient email address subject: str (optional) email subject message: str (optional) message to send Returns ------- nothing. Raises ------ SMTPHeloError: The server didn't reply properly to the helo greeting. SMTPAuthenticationError: The server didn't accept the username/password combination. SMTPException: No suitable authentication method was found. SMTPRecipientsRefused: The server rejected ALL recipients (no mail was sent). SMTPSenderRefused: The server didn't accept the from_addr. SMTPDataError: The server replied with an unexpected error code (other than a refusal of a recipient). """ if is_blank (recipient): raise IllegalArgumentException("recipient is required.") # ensure valid GMail Account gmail_account = ini_config.get("Email", "GMAIL_ACCOUNT") is_valid = validate_email(gmail_account) if(not is_valid): raise IllegalArgumentException( "GMail Account [{0}] is not valid email address" .format(gmail_account)) gmail_user = ini_config.get("Email", "GMAIL_ACCOUNT") gmail_password = ini_config.get("Email", "GMAIL_PASSWORD") logging.debug("Sending email using Gmail account [{0}] " "to recipient [{1}]" .format(gmail_user, recipient)) is_valid = validate_email(recipient) if(not is_valid): raise IllegalArgumentException( "Recipient [{0}] is not valid email address" .format(recipient)) msg = MIMEMultipart() msg['From'] = gmail_user msg['To'] = recipient msg['Subject'] = subject msg.attach(MIMEText(message)) logging.debug("Sending email to [{0}] using Gmail account [{1}]" .format(recipient, gmail_user)) mail_server = smtplib.SMTP_SSL('smtp.gmail.com', 465) mail_server.login(gmail_user, gmail_password) failed_recipients = mail_server.sendmail( gmail_user, recipient, msg.as_string()) if failed_recipients: logging.warn("Email failed to following recipients [{0}]" .format(failed_recipients)) mail_server.close() return