def pluginRequest(): Functions.log("DBG", "Start plugin request", "CORE") singleton = Singleton() for plugin in singleton.plugins: plugin.runPlugin() influxData = plugin.influxData() sendToInflux(influxData) sendToMqtt(influxData)
def __init__(self): self.starttime = datetime.datetime.now() self.endtime = "" self.singleton = Singleton() Functions.log( "DBG", "Instanciation of a Connector Class on " + self.singleton.hostName + " start=" + str(self.starttime), "CORE") self.populateDevices() self.connect()
def runWebApp(self, app): try: Functions.log("DBG", "Trying to start", "site") app.run(self.singleton.parameters["httpBind"], self.singleton.parameters["httpPort"], self.singleton.parameters["webserverDebug"]) except E: Functions.log("ERR", "Error for starting web", "site")
def startPlugins(): Functions.log("DBG", "Start plugins now", "CORE") singleton = Singleton() try: singleton.internalScheduler.add_job( pluginRequest, 'interval', seconds=singleton.parameters["queryPluginInterval"]) except Exception as err: Functions.log("ERR", "Error with scheduler " + str(err), "CORE")
def checkParameter(args): Functions.log("INF", "Entering in checkParameter #parameters=" + str(len(args)), "CORE") if (len(args) == 1): Functions.log( "DEAD", "At least provide one parameter : Configuration file for daemon", "CORE") return 0 return 1
def create_app(self): # create and configure the app template_dir = os.path.abspath('./web/templates') static_dir = os.path.abspath('./web/static') app = Flask("PimpMySuperWatt", instance_relative_config=True, template_folder=template_dir, static_folder=static_dir) # For disabling cache, usefull for online html/css/js script modifications app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 1 app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['EXPLAIN_TEMPLATE_LOADING'] = True cache = Cache(config={'CACHE_TYPE': 'null'}) cache.init_app(app) # ensure the instance folder exists try: os.makedirs(app.instance_path) except OSError: pass @app.route('/') @cache.cached(timeout=1) def index(): cache.clear() return render_template('index.html') @app.route('/parameters') def parameters(): return json.dumps(self.singleton.parameters, indent=4) @app.route('/inverterParameters') def inverterParameters(): singleton = Singleton() return { "qpi": singleton.QPI, "qid": singleton.QID, "qfw": singleton.QVFW, "qfw2": singleton.QVFW2, } @app.route('/inverterQuery') def inverterQuery(): singleton = Singleton() return singleton.QPIGS self.singleton.scheduler.init_app(app) self.singleton.scheduler.start() app.run(self.singleton.parameters["httpBind"], self.singleton.parameters["httpPort"]) Functions.log("DBG", "Site instance started", "site")
def checkConfiguration(self): if not self.retreiveInfluxDbConf(): Functions.log( "DEAD", "Error getting data from conf file about influxdb properties", "CORE") return 0 if not self.retreivePowerManagerGeneralConfig(): Functions.log( "DEAD", "Error getting data from conf file about general configuration for daemon", "CORE") return 0 return 1
def __init__(self, conDict): Functions.log("INF", "Creating a new influxDb connector onbjet instance", "myInfluxdb") self.host = conDict['host'] self.port = conDict['port'] self.database = conDict['database'] Functions.log( "INF", "Opening connection to influx with host=" + str(conDict['host']) + ",port=" + str(conDict['port']) + ",database=" + conDict['database'], "myInfluxDb") self.clientConn = InfluxDBClient(host=conDict['host'], port=conDict['port'], database=conDict['database'])
def __init__(self, pinNum=36): Functions.log("INF", "Creating a new grid Power instance ", "gridPower") self.gridPowerWanted = True self.gridPowerStatus = "unknown" self.pinNumberForGridControl = pinNum self.errorStatus = 0 Functions.log( "INF", "Configuration for GPIO port on pin" + str(self.pinNumberForGridControl), "gridPower") GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) try: GPIO.setup(self.pinNumberForGridControl, GPIO.OUT) except RuntimeError as err: Functions.log("ERR", "Unable to open Gpio Port", "gridPower") Functions.log("ERR", err, "gridPower") self.errorStatus = 1 return except Warning as warn: Functions.log("WNG", warn, "gridPower")
def pimpMySuperWatt(): Functions.log("INF", "Instanciate Singleton", "CORE") singleton = Singleton() Functions.log("INF", "Starting PimpMySuperWatts on " + socket.gethostname(), "CORE") Functions.log("INF", "Analysing arguments", "CORE") parser = argparse.ArgumentParser() parser.add_argument( "configFile", help="The absolute path to the configuration file (pimpMySuperWatt.py)" ) parser.add_argument("--debug", help="Debug mode, more verbosity", action="store_true") args = parser.parse_args() checkParameter(args) # Web starting waitServer = threading.Thread(target=startWeb) waitServer.start() # Connector communication starting waitConnector = threading.Thread(target=startConnector) waitConnector.start() waitThread = threading.Thread(target=waitEnd) waitThread.start() startDaemons() startPlugins() waitServer.join()
def sendToMqtt(json_body): singleton = Singleton() if not singleton.parameters["mqttServers"] == "": Functions.log("DBG", "Sending now to mqtts", "CORE") for mqtt in singleton.parameters["mqttServers"]: Functions.log( "DBG", "Sending now to " + mqtt["mqttServer"] + ":" + str(mqtt["mqttServerPort"]) + " server now", "CORE") publish.single(topic=mqtt["mqttTopic"], payload=json.dumps(json_body), hostname=mqtt["mqttServer"], port=mqtt["mqttServerPort"]) else: Functions.log("DBG", "No mqtt target specified", "CORE") Functions.log("DBG", "End sending now to mqtts", "CORE")
def loadConfiguration(self): if not os.path.isfile(self.configurationFile): Functions.log("ERR", self.configurationFile + " does not exists !", "CORE") return 0 try: jsonFile = open(self.configurationFile) except Exception as err: Functions.log("ERR", "Error loading configuration file", "CORE") Functions.log("ERR", str(err), "CORE") return 0 with jsonFile as json_data: try: self.data_dict = json.load(json_data) except Exception as err: Functions.log("ERR", "Error parsing configuration file", "CORE") Functions.log("ERR", str(err), "CORE") jsonFile.close() return 0 jsonFile.close() self.confLoaded = 1 return 1
def sendToInflux(json_body): singleton = Singleton() if not singleton.parameters["influxDbUrls"] == "": Functions.log("DBG", "Sending now to influxdbs", "CORE") for db in singleton.parameters["influxDbUrls"]: Functions.log("DBG", "Sending now to " + db["dbHost"] + " database now", "CORE") dbUser = db["username"] dbPassword = db["password"] dbHost = db["dbHost"] dbPort = db["dbPort"] dbName = db["dbName"] Functions.log( "DBG", "Sending data to " + dbHost + ":" + dbPort + " user: "******" password: "******" database: " + dbName, "CORE") client = InfluxDBClient(dbHost, dbPort, dbUser, dbPassword, dbName) client.create_database(dbName) client.write_points(json_body) else: Functions.log("DBG", "No influxdb target specified", "CORE") Functions.log("DBG", "End sending now to influx", "CORE")
def startDaemons(): Functions.log("DBG", "Start daemons now", "CORE") singleton = Singleton() try: Functions.log( "DBG", "Add poolingRequest job to scheduler with " + str(singleton.parameters["queryPoolingInterval"]) + " sec(s) interval", "CORE") singleton.internalScheduler.add_job( poolingRequest, 'interval', seconds=singleton.parameters["queryPoolingInterval"]) except Exception as err: Functions.log("ERR", "Error with scheduler " + str(err), "CORE")
def startWeb(): singleton = Singleton() # Ok now check if we webserver is asked if singleton.parameters["webserver"]: Functions.log("DBG", "Webserver is asked, starting it", "CORE") importlib.import_module('web') Functions.log( "DBG", "Trying instanciation of " + str(singleton.parameters["webClass"]), "CORE") mod = importlib.import_module('.' + singleton.parameters["webClass"], package="web") aSiteClass = getattr(mod, singleton.parameters["webClass"]) singleton.instanceWebApp = aSiteClass() else: Functions.log("DBG", "Webserver not asked", "CORE")
def setGridOn(self): if not self.errorStatus: try: GPIO.output(self.pinNumberForGridControl, 1) except Exception as err: Functions.log("ERR", "Error importing changing powerGrid to on", "gridPower") Functions.log("ERR", err, "gridPower") GPIO.cleanup() self.gridPowerWanted = True else: Functions.log( "ERR", "Unable to set gridPower to off because of errorStatus into instance", "gridPower")
def retreivePowerManagerGeneralConfig(self): if not self.confLoaded: Functions.log("ERR", "Error configuration file not opened", "CORE") return 0 if "powerManagerGeneralConfig" in self.data_dict: arr = self.data_dict['powerManagerGeneralConfig'] if isinstance(arr, dict): for confKey in arr: if confKey == "gpioPort4Grid": self.gpioPort4Grid = arr[confKey] else: Functions.log("ERR", "Error in configuration file format", "CORE") return 0 else: Functions.log("ERR", "Error in configuration file format", "CORE") return 0 return 1
def retreiveInfluxDbConf(self): if not self.confLoaded: Functions.log("ERR", "Error configuration file not opened", "CORE") return 0 if "influxDbConfig" in self.data_dict: arr = self.data_dict['influxDbConfig'] if isinstance(arr, dict): for confKey in arr: if confKey == "influxDbUrl": self.influxDbUrl = arr[confKey] if confKey == "influxDbPort": self.influxDbPort = arr[confKey] if confKey == "influxDbName": self.influxDbName = arr[confKey] else: Functions.log("ERR", "Error in configuration file format", "CORE") return 0 else: Functions.log("ERR", "Error in configuration file format", "CORE") return 0 return 1
def checkParameter(args): singleton = Singleton() # If debug if args.debug: Functions.log("INF", "Debug activated", "CORE") singleton.debug = True # Populate version singleton.version = Functions.kommandShell("git log | head -6") # Read configuration file json configFile = os.path.abspath(args.configFile) if not os.path.isfile(configFile): Functions.log("DEAD", "File " + str(configFile) + " doesn't exist", "CORE") Functions.log("INF", "Config file exist " + configFile, "CORE") singleton.configFile = configFile # Setting current hostname & ip singleton.hostName = socket.gethostname() for ifaceName in interfaces(): addrs = ifaddresses(ifaceName) try: for subAdress in addrs[netifaces.AF_INET]: if subAdress["addr"] != "127.0.0.1": Functions.log( "INF", "Local ip detected " + str(subAdress["addr"]), "CORE") singleton.ip = str(subAdress["addr"]) except Exception as err: Functions.log("WNG", "Error while trying to detect local ip " + str(err), "CORE") pass # Parsing the configFile Functions.log("DBG", "Parsing configFile " + configFile, "CORE") try: jsonLine = Functions.loadFileInALine(configFile) singleton.parameters = json.loads(jsonLine) Functions.log( "DBG", "Json config file successfully loaded " + json.dumps(singleton.parameters, indent=4), "CORE") except Exception as err: Functions.log( "DEAD", "Can't parse file " + configFile + " is it a json file ? details " + str(err), "CORE") # Instanciate plugin intanciatePlugins()
def __init__(self): self.singleton = Singleton() Functions.log("DBG", "Site instance created starting site...", "site") self.create_app()
def intanciatePlugins(): singleton = Singleton() singleton.plugins = [] for file in sorted(glob.glob('plugins/*/*.py')): moduleName = os.path.basename(file.replace(".py", "")) try: Functions.log("DBG", "Loading plugins/" + moduleName + "/" + moduleName, "CORE") mod = importlib.import_module("plugins." + moduleName + "." + moduleName) Functions.log( "DBG", "End loading plugins/" + moduleName + "/" + moduleName, "CORE") Functions.log("DBG", "Trying dynamic instantiation " + moduleName, "CORE") aClass = getattr(mod, moduleName) instancePlugin = aClass() if isinstance(instancePlugin, abstractPlugin): Functions.log( "DBG", "Plugin " + str(instancePlugin.__class__.__name__.upper()) + " is an instance of AbstractPlugin, populating array", "CORE") singleton.plugins.append(instancePlugin) else: Functions.log( "ERR", "Plugin " + moduleName + " isn't an instance of AbstractPlugin did u extend abstractPlugin ?", "CORE") except Exception as err: Functions.log( "ERR", "Couldn't instantiate " + moduleName + " error " + str(err), "CORE")
def populateDevices(self): Functions.log("DBG", "populateDevices not implemented in AbstractConnector", "AbstractConnector")
def waitEnd(): while True: Functions.log("DBG", "PimpMySuperWatt still alive", "CORE") time.sleep(2)
def disconnect(self): Functions.log("DBG", "disconnect not implemented in AbstractConnector", "AbstractConnector")
def read(self): Functions.log("DBG", "read not implemented in AbstractConnector", "AbstractConnector")
def influxData(self): Functions.log("DBG","influxData not implemented in AbstractPlugin","AbstractPlugin")
def runPlugin(self): Functions.log("DBG","runPlugin not implemented in AbstractPlugin","AbstractPlugin")
def poolingRequest(): Functions.log("DBG", "Start pooling request", "CORE") singleton = Singleton() singleton.QPIGS = Functions.command("QPIGS", "") json_body = [{ "measurement": "pimpMySuperWatt", "tags": { "hostname": singleton.hostName, "version": singleton.version, "qpi": singleton.QPI, "qid": singleton.QID, "qfw": singleton.QVFW, "qfw2": singleton.QVFW2, "url": "http://" + singleton.ip + ":" + str(singleton.parameters["httpPort"]), "instance": singleton.parameters["instance"] }, "fields": singleton.QPIGS }] json_body_parameters = [{ "measurement": "pimpMySuperWatt_Parameters", "tags": { "hostname": singleton.hostName, "version": singleton.version, }, "fields": { "qpi": singleton.QPI, "qid": singleton.QID, "qfw": singleton.QVFW, "qfw2": singleton.QVFW2, "url": "http://" + singleton.ip + ":" + str(singleton.parameters["httpPort"]), "instance": singleton.parameters["instance"], "debug": singleton.parameters["debug"], "communicationClass": singleton.parameters["communicationClass"], "portPath": singleton.parameters["portPath"], "webserver": singleton.parameters["webserver"], "webserverDebug": singleton.parameters["webserverDebug"], "webClass": singleton.parameters["webClass"], "httpBind": singleton.parameters["httpBind"], "queryPoolingInterval": singleton.parameters["queryPoolingInterval"] } }] sendToInflux(json_body) sendToInflux(json_body_parameters) sendToMqtt(json_body) sendToMqtt(json_body_parameters)
def mqttData(self): Functions.log("DBG","mqttData not implemented in AbstractPlugin","AbstractPlugin")
def startConnector(): singleton = Singleton() Functions.log("DBG", "Start connector now", "CORE") # Ok let's start with connector checking importlib.import_module('communication') Functions.log( "DBG", "Trying instanciation of " + str(singleton.parameters["communicationClass"]), "CORE") if not singleton.parameters["communicationClass"] == "": try: Functions.log( "DBG", "Importing module communicationClass " + str(singleton.parameters["communicationClass"]), "CORE") modCom = importlib.import_module( '.' + singleton.parameters["communicationClass"], package="communication") Functions.log( "DBG", "Retrieving class object " + str(singleton.parameters["communicationClass"]), "CORE") aConnectorClass = getattr( modCom, singleton.parameters["communicationClass"]) singleton.connector = aConnectorClass() Functions.log("DBG", "Launching QPI command", "CORE") singleton.QPI = Functions.command("QPI", "") Functions.log("DBG", "Launching QID command", "CORE") singleton.QID = Functions.command("QID", "") Functions.log("DBG", "Launching QVFW command", "CORE") singleton.QVFW = Functions.command("QVFW", "") Functions.log("DBG", "Launching QVFW2 command", "CORE") singleton.QVFW2 = Functions.command("QVFW2", "") except Exception as err: Functions.log("ERR", "Connector exception " + str(err), "CORE") else: Functions.log("DBG", "No serial connector defined.", "CORE")