2018-11-04 00:47:26 +01:00
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
from importlib import import_module
|
2018-11-01 19:50:04 +01:00
|
|
|
|
2018-11-04 00:47:26 +01:00
|
|
|
import aiohttp
|
|
|
|
import yaml
|
|
|
|
from aiohttp import web
|
2019-01-05 20:43:48 +01:00
|
|
|
from cbpi.api import *
|
2018-12-31 00:22:00 +01:00
|
|
|
|
2019-01-05 20:43:48 +01:00
|
|
|
from cbpi.utils.utils import load_config, json_dumps
|
2018-11-04 00:47:26 +01:00
|
|
|
|
2018-12-29 00:27:19 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2018-11-04 00:47:26 +01:00
|
|
|
|
|
|
|
class PluginController():
|
|
|
|
|
|
|
|
modules = {}
|
2018-11-16 20:35:59 +01:00
|
|
|
types = {}
|
2018-11-04 00:47:26 +01:00
|
|
|
|
|
|
|
def __init__(self, cbpi):
|
|
|
|
self.cbpi = cbpi
|
|
|
|
self.cbpi.register(self, "/plugin")
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def load_plugin_list(self):
|
|
|
|
async with aiohttp.ClientSession() as session:
|
2018-12-10 22:13:28 +01:00
|
|
|
async with session.get('https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins_v4.yaml') as resp:
|
2018-11-04 00:47:26 +01:00
|
|
|
|
|
|
|
if(resp.status == 200):
|
|
|
|
|
|
|
|
data = yaml.load(await resp.text())
|
|
|
|
return data
|
|
|
|
|
2018-12-07 00:18:35 +01:00
|
|
|
def load_plugins(self):
|
2018-11-04 00:47:26 +01:00
|
|
|
|
2019-01-05 20:43:48 +01:00
|
|
|
this_directory = os.path.dirname(__file__)
|
2018-11-04 00:47:26 +01:00
|
|
|
|
2019-01-05 20:43:48 +01:00
|
|
|
for filename in os.listdir(os.path.join(this_directory, "../extension")):
|
|
|
|
|
|
|
|
if os.path.isdir(os.path.join(this_directory, "../extension/") + filename) is False or filename == "__pycache__":
|
2018-11-04 00:47:26 +01:00
|
|
|
continue
|
|
|
|
try:
|
|
|
|
logger.info("Trying to load plugin %s" % filename)
|
2019-01-05 20:43:48 +01:00
|
|
|
|
|
|
|
data = load_config(os.path.join(this_directory, "../extension/%s/config.yaml" % filename))
|
2018-11-04 00:47:26 +01:00
|
|
|
|
|
|
|
if(data.get("version") == 4):
|
|
|
|
|
2019-01-05 20:43:48 +01:00
|
|
|
self.modules[filename] = import_module("cbpi.extension.%s" % (filename))
|
2018-11-16 20:35:59 +01:00
|
|
|
self.modules[filename].setup(self.cbpi)
|
2018-12-31 00:22:00 +01:00
|
|
|
|
2018-11-04 00:47:26 +01:00
|
|
|
logger.info("Plugin %s loaded successful" % filename)
|
|
|
|
else:
|
2018-12-31 00:22:00 +01:00
|
|
|
logger.warning("Plugin %s is not supporting version 4" % filename)
|
2018-11-04 00:47:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(e)
|
|
|
|
|
2018-12-29 00:27:19 +01:00
|
|
|
def load_plugins_from_evn(self):
|
|
|
|
|
2018-12-31 00:22:00 +01:00
|
|
|
plugins = []
|
2019-01-05 20:43:48 +01:00
|
|
|
this_directory = os.path.dirname(__file__)
|
2019-01-08 19:45:23 +01:00
|
|
|
with open("./config/plugin_list.txt") as f:
|
|
|
|
|
|
|
|
print("###### LAD")
|
2018-12-31 00:22:00 +01:00
|
|
|
plugins = f.read().splitlines()
|
|
|
|
plugins = list(set(plugins))
|
2018-12-29 00:27:19 +01:00
|
|
|
|
|
|
|
for p in plugins:
|
2018-12-31 00:22:00 +01:00
|
|
|
logger.debug("Load Plugin %s" % p)
|
|
|
|
try:
|
|
|
|
logger.info("Try to load plugin: %s " % p)
|
|
|
|
self.modules[p] = import_module(p)
|
|
|
|
self.modules[p].setup(self.cbpi)
|
|
|
|
|
2018-12-29 00:27:19 +01:00
|
|
|
|
2018-12-31 00:22:00 +01:00
|
|
|
|
|
|
|
logger.info("Plugin %s loaded successfully" % p)
|
|
|
|
except Exception as e:
|
|
|
|
logger.error("FAILED to load plugin %s " % p)
|
|
|
|
logger.error(e)
|
2018-12-29 00:27:19 +01:00
|
|
|
|
|
|
|
|
2018-11-04 01:55:54 +01:00
|
|
|
@request_mapping(path="/plugins", method="GET", auth_required=False)
|
2018-11-04 00:47:26 +01:00
|
|
|
async def get_plugins(self, request):
|
|
|
|
"""
|
|
|
|
---
|
2018-11-16 20:35:59 +01:00
|
|
|
description: Get a list of avialable plugins
|
2018-11-04 00:47:26 +01:00
|
|
|
tags:
|
2018-11-16 20:35:59 +01:00
|
|
|
- Plugin
|
2018-11-04 00:47:26 +01:00
|
|
|
produces:
|
2018-11-16 20:35:59 +01:00
|
|
|
- application/json
|
2018-11-04 00:47:26 +01:00
|
|
|
responses:
|
|
|
|
"200":
|
|
|
|
description: successful operation. Return "pong" text
|
|
|
|
"405":
|
|
|
|
description: invalid HTTP Method
|
|
|
|
"""
|
|
|
|
return web.json_response(await self.load_plugin_list(), dumps=json_dumps)
|
|
|
|
|
2018-11-01 19:50:04 +01:00
|
|
|
|
|
|
|
|
2018-11-01 21:25:42 +01:00
|
|
|
def register(self, name, clazz) -> None:
|
|
|
|
'''
|
|
|
|
Register a new actor type
|
|
|
|
:param name: actor name
|
|
|
|
:param clazz: actor class
|
|
|
|
:return: None
|
|
|
|
'''
|
2018-12-31 00:22:00 +01:00
|
|
|
logger.info("Register %s Class %s" % (name, clazz.__name__))
|
2018-11-16 20:35:59 +01:00
|
|
|
if issubclass(clazz, CBPiActor):
|
2019-01-07 22:05:52 +01:00
|
|
|
#self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
|
|
|
|
self.cbpi.actor.types[name] = self._parse_props(clazz)
|
2018-11-16 20:35:59 +01:00
|
|
|
|
2018-11-18 15:40:10 +01:00
|
|
|
if issubclass(clazz, CBPiSensor):
|
2019-01-07 22:05:52 +01:00
|
|
|
self.cbpi.sensor.types[name] = self._parse_props(clazz)
|
2018-11-18 15:40:10 +01:00
|
|
|
|
|
|
|
if issubclass(clazz, CBPiKettleLogic):
|
2019-01-07 22:05:52 +01:00
|
|
|
self.cbpi.kettle.types[name] = self._parse_props(clazz)
|
2018-11-18 15:40:10 +01:00
|
|
|
|
2018-12-10 22:13:28 +01:00
|
|
|
if issubclass(clazz, CBPiSimpleStep):
|
2018-12-05 07:31:12 +01:00
|
|
|
self.cbpi.step.types[name] = self._parse_props(clazz)
|
2018-12-29 00:27:19 +01:00
|
|
|
|
2018-12-06 23:46:06 +01:00
|
|
|
if issubclass(clazz, CBPiExtension):
|
|
|
|
self.c = clazz(self.cbpi)
|
2018-11-01 19:50:04 +01:00
|
|
|
|
|
|
|
def _parse_props(self, cls):
|
2018-12-29 00:27:19 +01:00
|
|
|
|
2018-11-01 19:50:04 +01:00
|
|
|
name = cls.__name__
|
|
|
|
|
|
|
|
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
|
|
|
|
|
|
|
tmpObj = cls()
|
|
|
|
members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")]
|
|
|
|
for m in members:
|
|
|
|
if isinstance(tmpObj.__getattribute__(m), Property.Number):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append(
|
|
|
|
{"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description, "default_value": t.default_value})
|
|
|
|
elif isinstance(tmpObj.__getattribute__(m), Property.Text):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append(
|
|
|
|
{"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "default_value": t.default_value, "description": t.description})
|
|
|
|
elif isinstance(tmpObj.__getattribute__(m), Property.Select):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append(
|
|
|
|
{"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description})
|
|
|
|
elif isinstance(tmpObj.__getattribute__(m), Property.Actor):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description})
|
|
|
|
elif isinstance(tmpObj.__getattribute__(m), Property.Sensor):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description})
|
|
|
|
elif isinstance(tmpObj.__getattribute__(m), Property.Kettle):
|
|
|
|
t = tmpObj.__getattribute__(m)
|
|
|
|
result["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description})
|
|
|
|
|
|
|
|
for method_name, method in cls.__dict__.items():
|
2018-11-01 21:25:42 +01:00
|
|
|
if hasattr(method, "action"):
|
|
|
|
key = method.__getattribute__("key")
|
|
|
|
parameters = method.__getattribute__("parameters")
|
|
|
|
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
|
2018-12-29 00:27:19 +01:00
|
|
|
|
2018-12-05 07:31:12 +01:00
|
|
|
return result
|