def initialize_app(flask_app): """Apply application configuration. Load configuration to Flask object and apply configuration to it :param flask_app: Flask application to configure :type flask_app: Flask """ configure_app(flask_app) # Fix to handle properly X-Forwarded-Proto header # from werkzeug.contrib.fixers import ProxyFix flask_app.wsgi_app = ProxyFix(flask_app.wsgi_app) # Define base_url for the app blueprint = Blueprint('api', __name__, url_prefix=settings.API["base_url"]) api.init_app(blueprint) api.add_namespace(admin_ns) api.add_namespace(sensors_ns) api.add_namespace(phone_ns) # Define base_url from swaggerui resources (js, css...) api_doc = flask_restx.apidoc.apidoc api_doc.url_prefix = settings.API["base_url"] + "/doc" flask_app.register_blueprint(blueprint)
def get(self, env): """ Get current recording session. Get informations about the current recording session :param env: Environement identifier :type env: string """ self.logger.info("GET env=%s", env) args = PARSER.parse_args(request) time = args.get('time', None) svc = RecorderService() try: result = svc.load_session(env, time) self.logger.debug(result) except RecordingException as exc: api.abort(exc.http_status, exc.message) return result
def post(self, env): """ Start a session. Start a data recording session :param env: Environement identifier :type env: string """ data = request.json self.logger.info("POST env=%s scenario=%s step=%s", env, data.get("scenario"), data.get("step")) svc = RecorderService() try: result = svc.store_session(env, data.get("scenario"), data.get("step")) except RecordingException as exc: api.abort(exc.http_status, exc.message) return result
def delete(self, env): """ Stop a session. Stop a data recording session :param env: Environement identifier :type env: string """ self.logger.info("DELETE env=%s", env) svc = RecorderService() try: result = svc.load_session(env) svc.store_session(env, result.scenario, result.step, 0) except RecordingException as exc: api.abort(exc.http_status, exc.message) return result
def post(self, env): # pylint: disable=no-self-use """ Define current step. Define current step for a recording scenartion :param env: Environement identifier :type env: string """ recorder = RecorderService() data = request.json self.logger.info("POST step env=%s step=%s", env, data.get("step")) try: result = recorder.load_session(env) result.step = data.get("step") recorder.store_session(env, result.scenario, result.step) except RecordingException as exc: api.abort(exc.http_status, exc.message) return result
def initialize_app(flask_app): """Apply application configuration. Load configuration to Flask object and apply configuration to it :param flask_app: Flask application to configure :type flask_app: Flask """ configure_app(flask_app) flask_app.wsgi_app = ProxyFix(flask_app.wsgi_app) blueprint = Blueprint('api', __name__, url_prefix=settings.API["context_root"]) api.init_app(blueprint) api.add_namespace(equipements_namespace) #api.add_namespace(servers_namespace) api.add_namespace(recorder_namespace) api.add_namespace(monitoring_namespace) api_doc = flask_restx.apidoc.apidoc api_doc.url_prefix = settings.API["context_root"] + "/doc" flask_app.register_blueprint(blueprint) requests.urllib3.disable_warnings()
import logging import json import urllib import requests from flask_restx import Resource from flask import request import settings from api.datamodel import RUNNING_SCENARIO from api.datamodel import STEP_POST, RECORDER_POST from api.restx import API as api from service.datamodel import RunningScenarioClass from service.exception import RecordingException from service.recorder import RecorderService NS = api.namespace('recorders', description='Recording sessions management') PARSER = api.parser() PARSER.add_argument( 'time', type=int, help='POSIX Timestamp (in nanosec) recorder started immediatly \ before this time', default=None, location='args') @NS.route('/environment/<string:env>') @api.doc(params={'env': 'Environment identifier'}) class Recorder(Resource): """Recorder services management class."""
# All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 """FFBC8 weatherstation receive phone/browser data.""" import logging import socket import subprocess from flask import request from flask_restx import Resource import requests from api.restx import API import settings NS = API.namespace('phone', description='interact with phone') @NS.route('/GPS') class GPS(Resource): """Receive GPS data API Class.""" logger = None # pylint: disable=keyword-arg-before-vararg def __init__(self, api=None, *args, **kwargs): Resource.__init__(self, api, kwargs) self.logger = logging.getLogger(__name__) def _send_influx(self, data): if data == "":
# All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 """FFBC8 weatherstation Admin API.""" import logging from flask import request from flask_restx import Resource from api.datamodel import SYSTEM_COMMAND_PAYLOAD, SYSTEM_TIME,\ WIFI_CONFIG_EXTENDED, WIFI_CONFIG from api.restx import API from services.admin import AdminService NS = API.namespace('admin', description='Weather station admin') @NS.route("/ping") class Pinger(Resource): """System pingers.""" logger = None # pylint: disable=keyword-arg-before-vararg def __init__(self, api=None, *args, **kwargs): Resource.__init__(self, api, kwargs) self.logger = logging.getLogger(__name__) def get(self): """Ping system."""
# -*- coding: utf-8 -*- # Copyright (c) 2020 Zorglub42 {contact(at)zorglub42.fr}. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 """FFBC8 weatherstation data model.""" from flask_restx import fields from api.restx import API # Model desecription for methods parameters SYSTEM_COMMAND_PAYLOAD = API.model("systemCommand", { "command": fields.String( requied=True, description="Command to execute", enum=["shutdown", "reboot"] ) }) SYSTEM_TIME = API.model("dateTime", { "dateTime": fields.String( requied=True, description="Date is ISO format", example="2020-02-21T20:36:28Z" ) }) SENSOR_VALUE = API.model("sensorValue", { 'name': fields.String( required=True, description='Sensor name',
def post(self, server): # pylint: disable=locally-disabled,no-self-use """ Power consumption receiver (see /equipments/{equipement}/measurements). Use instead /equipments/{equipement}/measurements with <code>[{"sensor": "power", "unit": "W", "value": power-value}]</code> as measurements payload<hr> Store a new power consumption measurement for a particular server :param server: Environement identifier :type server: string """ data = request.json recorder_manager = RecorderService() self.log.info("POST server %s consumption %s in environment %s", server, data.get("power"), data.get("environment")) time = data.get("time", None) try: recorder = recorder_manager.load_session(data.get("environment"), time) except RecordingException as exc: if exc.http_status == 404: if settings.ALWAYS_RECORD: recorder = RunningScenarioClass(data.get("environment"), "n/s", "n/s") else: raise exc result = PowerMeasurementClass(recorder.environment, data.get("power"), recorder.scenario, recorder.step) influx_data = "PowerMeasurement,hardware=" influx_data += server.replace(' ', '\\ ') influx_data += ",environment=" influx_data += result.environment.replace(' ', '\\ ') influx_data += ",scenario=" influx_data += result.scenario.replace(' ', '\\ ') influx_data += ",step=" influx_data += result.step.replace(' ', '\\ ') influx_data += " power=" influx_data += str(data.get("power")) if time is not None: influx_data = influx_data + " " + str(time) if settings.INFLUX["user"] is not None: auth = (settings.INFLUX["user"], settings.INFLUX["pass"]) else: auth = None influx_url = settings.INFLUX["host"] + "/write?db=" influx_url += settings.INFLUX["db"] response = requests.post(influx_url, data=influx_data, auth=auth, verify=False) if response.status_code != 204: log_msg = "Error while storing measurment: {}" log_msg = log_msg.format(response.text) api.abort(500, log_msg) influx_data = "SensorMeasurement,equipement=" influx_data += server.replace(' ', '\\ ') influx_data += ",environment=" influx_data += recorder.environment.replace(' ', '\\ ') influx_data += ",scenario=" influx_data += recorder.scenario.replace(' ', '\\ ') influx_data += ",step=" influx_data += recorder.step.replace(' ', '\\ ') influx_data += ",sensor=power" influx_data += ",unit=W" influx_data += " value=" influx_data += str(data["power"]) response = requests.post(influx_url, data=influx_data, auth=auth, verify=False) if response.status_code != 204: log_msg = "Error while storing measurment: {}" log_msg = log_msg.format(response.text) api.abort(500, log_msg) return result
# 1.0.0 - 2017-02-20 : Release of the file # import logging import requests from flask import request from flask_restx import Resource import settings from api.datamodel import POWER_MEASUREMENT, POWER_POST from api.restx import API as api from service.datamodel import PowerMeasurementClass, RunningScenarioClass from service.exception import RecordingException from service.recorder import RecorderService NS = api.namespace('servers', description='Operations related to servers') @NS.route('/<string:server>/consumption') @NS.deprecated class ServerConsumption(Resource): """Server consumption management API.""" log = logging.getLogger(__name__) @api.expect(POWER_POST) @api.marshal_with(POWER_MEASUREMENT) def post(self, server): # pylint: disable=locally-disabled,no-self-use """ Power consumption receiver (see /equipments/{equipement}/measurements).
# # Description : # API monitoring # ------------------------------------------------------- # History : # 1.0.0 - 2017-05-11 : Release of the file # import logging from flask_restx import Resource from api.datamodel import API_STATUS from api.restx import API as api from service.monitoring import MonitoringService NS = api.namespace('monitoring', description='API monitoring') @NS.route('/ping') class Ping(Resource): """API monitoring Ping class.""" logger = logging.getLogger(__name__) @api.marshal_with(API_STATUS) def get(self): """Return API status.""" self.logger.debug("GET ping") return MonitoringService().connect_influx()
def post(self, equipement): # pylint: disable=locally-disabled,no-self-use """ Measurements receiver. Store new measurements for a particular equipement :param equipement: Equipement identifier :type equipement: string """ data = request.json recorder_manager = RecorderService() self.log.info("POST measurements for equiment %s in environment %s", equipement, data.get("environment")) time = data.get("time", None) try: recorder = recorder_manager.load_session(data.get("environment"), time) except RecordingException as exc: if exc.http_status == 404: if settings.ALWAYS_RECORD: recorder = RunningScenarioClass(data.get("environment"), "n/s", "n/s") else: raise exc result = APIStatusClass("OK") sm_influx_data = "" pm_influx_data = "" for measurement in data["measurements"]: time = measurement.get("time", None) if sm_influx_data != "": sm_influx_data += "\n" sm_influx_data += "SensorMeasurement,equipement=" sm_influx_data += equipement.replace(' ', '\\ ') sm_influx_data += ",environment=" sm_influx_data += recorder.environment.replace(' ', '\\ ') sm_influx_data += ",scenario=" sm_influx_data += recorder.scenario.replace(' ', '\\ ') sm_influx_data += ",step=" sm_influx_data += recorder.step.replace(' ', '\\ ') sm_influx_data += ",sensor=" sm_influx_data += measurement["sensor"].replace(' ', '\\ ') sm_influx_data += ",unit=" sm_influx_data += measurement["unit"].replace(' ', '\\ ') sm_influx_data += " value=" sm_influx_data += str(measurement["value"]) if time and time > 10e+9: #Introduce aleat of 0..9999 nano sec to avoid data mixup sm_time = time + random.randint(0, 9999) sm_influx_data = sm_influx_data + " " + str(sm_time) self._mqtt_svc.publish(recorder.environment, equipement, recorder.scenario, recorder.step, measurement["sensor"], measurement["unit"], measurement["value"], time) if measurement["sensor"] == "power": if pm_influx_data != "": pm_influx_data += "\n" pm_influx_data = "PowerMeasurement,hardware=" pm_influx_data += equipement.replace(' ', '\\ ') pm_influx_data += ",environment=" pm_influx_data += recorder.environment.replace(' ', '\\ ') pm_influx_data += ",scenario=" pm_influx_data += recorder.scenario.replace(' ', '\\ ') pm_influx_data += ",step=" pm_influx_data += recorder.step.replace(' ', '\\ ') pm_influx_data += " power=" pm_influx_data += str(measurement["value"]) if settings.INFLUX["user"] is not None: auth = (settings.INFLUX["user"], settings.INFLUX["pass"]) else: auth = None influx_url = settings.INFLUX["host"] + "/write?db=" influx_url += settings.INFLUX["db"] response = requests.post(influx_url, data=sm_influx_data.encode("utf-8"), auth=auth, headers={ "Content-Type": "application/x-www-form-urlencoded; " + "charset=UTF-8" }, verify=False) if response.status_code != 204: log_msg = "Error while storing measurment: {}" log_msg = log_msg.format(response.text) api.abort(500, log_msg) response = requests.post( influx_url, data=pm_influx_data.encode("utf-8"), auth=auth, headers={ "Content-Type": "application/x-www-form-urlencoded; " + "charset=UTF-8" }, verify=False) if response.status_code != 204: log_msg = "Error while storing measurment: {}" log_msg = log_msg.format(response.text) api.abort(500, log_msg) self.log.info("POST measurements done!") return result
import requests from flask import request from flask_restx import Resource from service.mqtt import MQTTService import settings from api.datamodel import API_STATUS, MEASUREMENT_POST from api.restx import API as api from service.datamodel import APIStatusClass, RunningScenarioClass from service.exception import RecordingException from service.recorder import RecorderService from service.mqtt import MQTTService NS = api.namespace('equipments', description='Equipements monitoring operations') @NS.route('/<string:equipement>/measurements') class EquipementMeasurements(Resource): """Server consumption management API.""" log = logging.getLogger(__name__) def __init__(self, api=None, *args, **kwargs): super().__init__(api, *args, **kwargs) self._mqtt_svc = MQTTService() @api.expect(MEASUREMENT_POST) @api.marshal_with(API_STATUS) def post(self, equipement): # pylint: disable=locally-disabled,no-self-use
# Description : # Public data model definitions # ------------------------------------------------------- # History : # 1.0.0 - 2017-02-20 : Release of the file # from flask_restx import fields from api.restx import API # Model desecription for methods parameters POWER_POST = API.model( 'powerPost', { 'power': fields.Integer(required=True, description='Power consumption in Watts'), 'time': fields.Integer(required=False, description='Measurment time stamp'), 'environment': fields.String(required=True, description='Recorder environment \ identifier'), }) MEASUREMENT = API.model( "measurement", { 'sensor': fields.String(required=True, description="Sensor/measurment name"), 'unit': fields.String(required=True, description='Measurement unit'), 'value': fields.Float(required=True, decription='Measurement value'), 'time': fields.Integer(
# -*- coding: utf-8 -*- # Copyright (c) 2020 Zorglub42 {contact(at)zorglub42.fr}. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 """FFBC8 weatherstation sensors API.""" import logging from flask_restx import Resource, reqparse from api.datamodel import (LAST_SENSORS_VALUES, GET_SENSOR_VALUES, SENSOR_VALUES_TREND) from api.restx import API from services.sensors import SensorsService NS = API.namespace('sensors', description='sensors resources') @NS.route('/last') class Last(Resource): """Last value for all sensors API Class.""" logger = None # pylint: disable=keyword-arg-before-vararg def __init__(self, api=None, *args, **kwargs): Resource.__init__(self, api, kwargs) self.logger = logging.getLogger(__name__) @API.marshal_with(LAST_SENSORS_VALUES) def get(self):
# # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 """FFBC8 weatherstation receive GPS data.""" import logging from flask import request from flask_restx import Resource import requests from api.restx import API import settings NS = API.namespace( 'GPS', description='receive GPS data' ) @NS.route('/') class GPS(Resource): """Receive GPS data API Class.""" logger = None # pylint: disable=keyword-arg-before-vararg def __init__(self, api=None, *args, **kwargs): Resource.__init__(self, api, kwargs) self.logger = logging.getLogger(__name__) def _send_influx(self, data):