mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-12-22 13:34:55 +01:00
rework database
This commit is contained in:
parent
05e08d0dc6
commit
296c2c69f0
46 changed files with 1402 additions and 2390 deletions
|
@ -1,2 +1,3 @@
|
||||||
recursive-include cbpi/config *
|
recursive-include cbpi/config *
|
||||||
recursive-include cbpi/extension *
|
recursive-include cbpi/extension *
|
||||||
|
recursive-include cbpi/static *
|
|
@ -0,0 +1 @@
|
||||||
|
__version__ = "4.0.0.8"
|
|
@ -1,4 +1,5 @@
|
||||||
__all__ = ["CBPiActor",
|
__all__ = ["CBPiActor",
|
||||||
|
"CBPiActor2",
|
||||||
"CBPiExtension",
|
"CBPiExtension",
|
||||||
"Property",
|
"Property",
|
||||||
"PropertyType",
|
"PropertyType",
|
||||||
|
@ -9,12 +10,14 @@ __all__ = ["CBPiActor",
|
||||||
"parameters",
|
"parameters",
|
||||||
"background_task",
|
"background_task",
|
||||||
"CBPiKettleLogic",
|
"CBPiKettleLogic",
|
||||||
|
"CBPiKettleLogic2",
|
||||||
"CBPiSimpleStep",
|
"CBPiSimpleStep",
|
||||||
"CBPiException",
|
"CBPiException",
|
||||||
"KettleException",
|
"KettleException",
|
||||||
"SensorException",
|
"SensorException",
|
||||||
"ActorException",
|
"ActorException",
|
||||||
"CBPiSensor",
|
"CBPiSensor",
|
||||||
|
"CBPiSensor2",
|
||||||
"CBPiStep"]
|
"CBPiStep"]
|
||||||
|
|
||||||
from cbpi.api.actor import *
|
from cbpi.api.actor import *
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
|
import asyncio
|
||||||
from cbpi.api.extension import CBPiExtension
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
|
||||||
__all__ = ["CBPiActor"]
|
__all__ = ["CBPiActor", "CBPiActor2"]
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -45,3 +45,57 @@ class CBPiActor(CBPiExtension, metaclass=ABCMeta):
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class CBPiActor2(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, props):
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.id = id
|
||||||
|
self.props = props
|
||||||
|
self.logger = logging.getLogger(__file__)
|
||||||
|
self.data_logger = None
|
||||||
|
self.state = False
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log_data(self, value):
|
||||||
|
self.cbpi.log.log_data(self.id, value)
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
while self.running:
|
||||||
|
print("RUNNING ACTOR")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
print("########STATE", self.state)
|
||||||
|
return dict(state=self.state)
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
|
||||||
|
print("START UP ACTOR")
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
async def on(self, power):
|
||||||
|
'''
|
||||||
|
Code to switch the actor on. Power is provided as integer value
|
||||||
|
|
||||||
|
:param power: power value between 0 and 100
|
||||||
|
:return: None
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def off(self):
|
||||||
|
|
||||||
|
'''
|
||||||
|
Code to switch the actor off
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from cbpi.api.extension import CBPiExtension
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
from abc import ABCMeta
|
||||||
|
import logging
|
||||||
|
import asyncio
|
||||||
|
|
||||||
class CBPiKettleLogic(CBPiExtension):
|
class CBPiKettleLogic(CBPiExtension):
|
||||||
|
|
||||||
|
@ -36,3 +38,60 @@ class CBPiKettleLogic(CBPiExtension):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiKettleLogic2(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, props):
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.id = id
|
||||||
|
self.props = props
|
||||||
|
self.logger = logging.getLogger(__file__)
|
||||||
|
self.data_logger = None
|
||||||
|
self.state = False
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log_data(self, value):
|
||||||
|
self.cbpi.log.log_data(self.id, value)
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
while self.running:
|
||||||
|
print("RUNNING KETTLE")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
print("########STATE", self.state)
|
||||||
|
return dict(state=self.state)
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
print("")
|
||||||
|
print("")
|
||||||
|
print("")
|
||||||
|
print("##################START UP KETTLE")
|
||||||
|
print("")
|
||||||
|
print("")
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
async def on(self, power):
|
||||||
|
'''
|
||||||
|
Code to switch the actor on. Power is provided as integer value
|
||||||
|
|
||||||
|
:param power: power value between 0 and 100
|
||||||
|
:return: None
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def off(self):
|
||||||
|
|
||||||
|
'''
|
||||||
|
Code to switch the actor off
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
from abc import ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
|
|
||||||
from cbpi.api.extension import CBPiExtension
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,3 +31,40 @@ class CBPiSensor(CBPiExtension, metaclass=ABCMeta):
|
||||||
|
|
||||||
def get_unit(self):
|
def get_unit(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class CBPiSensor2(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
def __init__(self, cbpi, id, props):
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.id = id
|
||||||
|
self.props = props
|
||||||
|
self.logger = logging.getLogger(__file__)
|
||||||
|
self.data_logger = None
|
||||||
|
self.state = False
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def log_data(self, value):
|
||||||
|
self.cbpi.log.log_data(self.id, value)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def run(self):
|
||||||
|
self.logger.warning("Sensor Init not implemented")
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_unit(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
|
||||||
|
self.running = False
|
|
@ -39,7 +39,7 @@ class CBPiStep(metaclass=ABCMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def update(self, props):
|
async def update(self, props):
|
||||||
await self.cbpi.step2.update_props(self.id, props)
|
await self.cbpi.step.update_props(self.id, props)
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
while self.running:
|
while self.running:
|
||||||
|
|
|
@ -14,6 +14,7 @@ import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_plugin_file():
|
def create_plugin_file():
|
||||||
import os.path
|
import os.path
|
||||||
if os.path.exists(os.path.join(".", 'config', "plugin_list.txt")) is False:
|
if os.path.exists(os.path.join(".", 'config', "plugin_list.txt")) is False:
|
||||||
|
@ -144,10 +145,16 @@ def main():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Welcome to CraftBeerPi 4')
|
parser = argparse.ArgumentParser(description='Welcome to CraftBeerPi 4')
|
||||||
parser.add_argument("action", type=str, help="start,stop,restart,setup,plugins")
|
parser.add_argument("action", type=str, help="start,stop,restart,setup,plugins")
|
||||||
|
parser.add_argument('--debug', dest='debug', action='store_true')
|
||||||
parser.add_argument("--name", type=str, help="Plugin name")
|
parser.add_argument("--name", type=str, help="Plugin name")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.debug is True:
|
||||||
|
level =logging.DEBUG
|
||||||
|
else:
|
||||||
|
level =logging.INFO
|
||||||
#logging.basicConfig(level=logging.INFO, filename='./logs/app.log', filemode='a', format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
#logging.basicConfig(level=logging.INFO, filename='./logs/app.log', filemode='a', format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
logging.basicConfig(level=level, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
||||||
|
|
||||||
if args.action == "setup":
|
if args.action == "setup":
|
||||||
print("Setting up CBPi")
|
print("Setting up CBPi")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
name: CraftBeerPi
|
name: CraftBeerPi
|
||||||
version: 4.0.1_alpha
|
version: 4.0.8
|
||||||
|
|
||||||
#: /myext
|
#: /myext
|
||||||
|
|
||||||
|
|
|
@ -1,157 +1,43 @@
|
||||||
import asyncio
|
from cbpi.controller.basic_controller import BasicController
|
||||||
import logging
|
import logging
|
||||||
|
from tabulate import tabulate
|
||||||
from voluptuous import Schema
|
class ActorController(BasicController):
|
||||||
|
|
||||||
from cbpi.api import *
|
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
|
||||||
from cbpi.database.model import ActorModel
|
|
||||||
|
|
||||||
|
|
||||||
class ActorController(CRUDController):
|
|
||||||
'''
|
|
||||||
The main actor controller
|
|
||||||
'''
|
|
||||||
model = ActorModel
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super(ActorController, self).__init__(cbpi)
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.state = False;
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.cbpi.register(self)
|
|
||||||
self.types = {}
|
|
||||||
self.actors = {}
|
|
||||||
|
|
||||||
async def init(self):
|
|
||||||
"""
|
|
||||||
This method initializes all actors during startup. It creates actor instances
|
|
||||||
|
|
||||||
:return:
|
super(ActorController, self).__init__(cbpi, "actor.json")
|
||||||
"""
|
|
||||||
await super(ActorController, self).init()
|
|
||||||
for id, value in self.cache.items():
|
|
||||||
await self._init_actor(value)
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return dict(items=self.cache,types=self.types)
|
|
||||||
|
|
||||||
async def _init_actor(self, actor):
|
|
||||||
|
|
||||||
|
async def on(self, id):
|
||||||
try:
|
try:
|
||||||
if actor.type in self.types:
|
item = self.find_by_id(id)
|
||||||
cfg = actor.config.copy()
|
instance = item.get("instance")
|
||||||
cfg.update(dict(cbpi=self.cbpi, id=id, name=actor.name))
|
await instance.on()
|
||||||
clazz = self.types[actor.type]["class"];
|
|
||||||
self.cache[actor.id].instance = clazz(**cfg)
|
|
||||||
self.cache[actor.id].instance.init()
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/initialized" % actor.id, id=actor.id)
|
|
||||||
else:
|
|
||||||
self.logger.error("Actor type '%s' not found (Available Actor Types: %s)" % (actor.type, ', '.join(self.types.keys())))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
||||||
self.logger.error("Failed to init actor %s - Reason %s" % (actor.id, str(e)))
|
async def off(self, id):
|
||||||
|
try:
|
||||||
|
item = self.find_by_id(id)
|
||||||
|
instance = item.get("instance")
|
||||||
|
await instance.off()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
|
|
||||||
async def _stop_actor(self, actor):
|
async def toogle(self, id):
|
||||||
actor.instance.stop()
|
try:
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/stopped" % actor.id, id=actor.id)
|
item = self.find_by_id(id)
|
||||||
|
instance = item.get("instance")
|
||||||
@on_event(topic="actor/+/switch/on")
|
await instance.toggle()
|
||||||
async def on(self, actor_id, power=100, **kwargs) -> None:
|
except Exception as e:
|
||||||
"""
|
logging.error("Faild to switch on Actor {} {}".format(id, e))
|
||||||
Method to switch an actor on.
|
|
||||||
Supporting Event Topic "actor/+/on"
|
|
||||||
|
|
||||||
:param actor_id: the actor id
|
|
||||||
:param future
|
|
||||||
:param power: as integer value between 1 and 100
|
|
||||||
:param kwargs:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
actor_id = int(actor_id)
|
|
||||||
if actor_id in self.cache:
|
|
||||||
|
|
||||||
self.logger.debug("ON %s" % actor_id)
|
|
||||||
actor = self.cache[actor_id].instance
|
|
||||||
actor.on(power)
|
|
||||||
await self.cbpi.bus.fire("actor/%s/on/ok" % actor_id)
|
|
||||||
|
|
||||||
|
|
||||||
@on_event(topic="actor/+/toggle")
|
def create_dict(self, data):
|
||||||
async def toggle(self, actor_id, power=100, time=None, **kwargs) -> None:
|
try:
|
||||||
"""
|
instance = data.get("instance")
|
||||||
Method to toggle an actor on or off
|
state = state=instance.get_state()
|
||||||
Supporting Event Topic "actor/+/toggle"
|
except Exception as e:
|
||||||
|
logging.error("Faild to crate actor dict {} ".format(e))
|
||||||
:param actor_id: the actor actor_id
|
state = dict()
|
||||||
:param power: the power as integer between 0 and 100
|
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), state=state,props=data.get("props", []))
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.logger.debug("TOGGLE %s" % actor_id)
|
|
||||||
actor_id = int(actor_id)
|
|
||||||
if actor_id in self.cache:
|
|
||||||
actor = self.cache[actor_id].instance
|
|
||||||
|
|
||||||
if actor.state is True:
|
|
||||||
await self.off(actor_id=actor_id)
|
|
||||||
else:
|
|
||||||
await self.on(actor_id=actor_id)
|
|
||||||
|
|
||||||
if time is not None:
|
|
||||||
async def time_toggle(cbpi, actor_id, time):
|
|
||||||
await asyncio.sleep(time)
|
|
||||||
await cbpi.bus.fire("actor/%s/off" % actor_id, actor_id = actor_id)
|
|
||||||
await self.cbpi.job.start_job(time_toggle(self.cbpi, actor_id, time), "actor_%s_time_toggle" % actor_id, "actor_toggle")
|
|
||||||
|
|
||||||
|
|
||||||
@on_event(topic="actor/+/off")
|
|
||||||
async def off(self, actor_id, **kwargs) -> None:
|
|
||||||
"""
|
|
||||||
Method to switch and actor off
|
|
||||||
Supporting Event Topic "actor/+/off"
|
|
||||||
|
|
||||||
:param actor_id: the actor actor_id
|
|
||||||
:param kwargs:
|
|
||||||
"""
|
|
||||||
self.logger.debug("OFF %s" % actor_id)
|
|
||||||
actor_id = int(actor_id)
|
|
||||||
|
|
||||||
if actor_id in self.cache:
|
|
||||||
actor = self.cache[actor_id].instance
|
|
||||||
actor.off()
|
|
||||||
await self.cbpi.bus.fire("actor/%s/off/ok" % actor_id)
|
|
||||||
|
|
||||||
@on_event(topic="actor/+/action")
|
|
||||||
async def call_action(self, actor_id, data, **kwargs) -> None:
|
|
||||||
|
|
||||||
schema = Schema({"name":str, "parameter":dict})
|
|
||||||
schema(data)
|
|
||||||
name = data.get("name")
|
|
||||||
parameter = data.get("parameter")
|
|
||||||
actor = self.cache[actor_id].instance.__getattribute__(name)(**parameter)
|
|
||||||
|
|
||||||
async def _post_add_callback(self, m):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param m:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
await self._init_actor(m)
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _pre_delete_callback(self, actor_id):
|
|
||||||
if hasattr(self.cache[int(actor_id)], "instance") and self.cache[int(actor_id)].instance is not None:
|
|
||||||
await self._stop_actor(self.cache[int(actor_id)])
|
|
||||||
|
|
||||||
async def _pre_update_callback(self, actor):
|
|
||||||
if hasattr(actor, "instance") and actor.instance is not None:
|
|
||||||
await self._stop_actor(actor)
|
|
||||||
|
|
||||||
async def _post_update_callback(self, actor):
|
|
||||||
|
|
||||||
await self._init_actor(actor)
|
|
148
cbpi/controller/basic_controller.py
Normal file
148
cbpi/controller/basic_controller.py
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os.path
|
||||||
|
import json
|
||||||
|
import sys, os
|
||||||
|
import shortuuid
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
class BasicController:
|
||||||
|
|
||||||
|
def __init__(self, cbpi, file):
|
||||||
|
self.name = self.__class__.__name__
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.cbpi.register(self)
|
||||||
|
self.service = self
|
||||||
|
self.types = {}
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.data = []
|
||||||
|
self.autostart = True
|
||||||
|
self._loop = asyncio.get_event_loop()
|
||||||
|
self.path = os.path.join(".", 'config', file)
|
||||||
|
self.cbpi.app.on_cleanup.append(self.shutdown)
|
||||||
|
|
||||||
|
async def init(self):
|
||||||
|
await self.load()
|
||||||
|
|
||||||
|
async def load(self):
|
||||||
|
logging.info("{} Load ".format(self.name))
|
||||||
|
with open(self.path) as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
|
||||||
|
self.data = data["data"]
|
||||||
|
|
||||||
|
if self.autostart is True:
|
||||||
|
for d in self.data:
|
||||||
|
logging.info("{} Starting ".format(self.name))
|
||||||
|
await self.start(d.get("id"))
|
||||||
|
|
||||||
|
async def save(self):
|
||||||
|
logging.info("{} Save ".format(self.name))
|
||||||
|
data = dict(data=list(map(lambda x: self.create_dict(x), self.data)))
|
||||||
|
with open(self.path, "w") as file:
|
||||||
|
json.dump(data, file, indent=4, sort_keys=True)
|
||||||
|
await self.push_udpate()
|
||||||
|
|
||||||
|
async def push_udpate(self):
|
||||||
|
await self.cbpi.bus.fire("sensor/update", data=list(map(lambda x: self.create_dict(x), self.data)))
|
||||||
|
|
||||||
|
def create_dict(self, data):
|
||||||
|
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), status=data.get("status"),props=data.get("props", []))
|
||||||
|
|
||||||
|
def find_by_id(self, id):
|
||||||
|
return next((item for item in self.data if item["id"] == id), None)
|
||||||
|
|
||||||
|
def get_index_by_id(self, id):
|
||||||
|
return next((i for i, item in enumerate(self.data) if item["id"] == id), None)
|
||||||
|
|
||||||
|
async def shutdown(self, app):
|
||||||
|
logging.info("{} Shutdown ".format(self.name))
|
||||||
|
tasks = []
|
||||||
|
for item in self.data:
|
||||||
|
if item.get("instance") is not None and item.get("instance").running is True:
|
||||||
|
await item.get("instance").stop()
|
||||||
|
tasks.append(item.get("instance").task)
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
await self.save()
|
||||||
|
|
||||||
|
async def stop(self, id):
|
||||||
|
logging.info("{} Stop Id {} ".format(self.name, id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
item = self.find_by_id(id)
|
||||||
|
instance = item.get("instance")
|
||||||
|
await instance.stop()
|
||||||
|
await instance.task
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("{} Cant stop {} - {}".format(self.name, id, e))
|
||||||
|
|
||||||
|
async def start(self, id):
|
||||||
|
logging.info("{} Start Id {} ".format(self.name, id))
|
||||||
|
try:
|
||||||
|
item = self.find_by_id(id)
|
||||||
|
instance = item.get("instance")
|
||||||
|
|
||||||
|
if instance is not None and instance.running is True:
|
||||||
|
logging.warning("{} already running {}".format(self.name, id))
|
||||||
|
return
|
||||||
|
|
||||||
|
type = item["type"]
|
||||||
|
print(type)
|
||||||
|
print(self.types)
|
||||||
|
clazz = self.types[type]["class"]
|
||||||
|
item["instance"] = clazz(self.cbpi, item["id"], {})
|
||||||
|
print(item["instance"])
|
||||||
|
await item["instance"].start()
|
||||||
|
item["instance"].task = self._loop.create_task(item["instance"].run())
|
||||||
|
logging.info("Sensor started {}".format(id))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("{} Cant start {} - {}".format(self.name, id, e))
|
||||||
|
|
||||||
|
def get_types(self):
|
||||||
|
logging.info("{} Get Types".format(self.name))
|
||||||
|
result = {}
|
||||||
|
for key, value in self.types.items():
|
||||||
|
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
logging.info("{} Get State".format(self.name))
|
||||||
|
return {"data": list(map(lambda x: self.create_dict(x), self.data)), "types":self.get_types()}
|
||||||
|
|
||||||
|
async def add(self, data):
|
||||||
|
logging.info("{} Add".format(self.name))
|
||||||
|
id = shortuuid.uuid()
|
||||||
|
item = {**data, "id": id, "instance": None , "name": data.get("name"), "props": data.get("props", {})}
|
||||||
|
self.data.append(item)
|
||||||
|
if self.autostart is True:
|
||||||
|
await self.start(id)
|
||||||
|
await self.save()
|
||||||
|
return item
|
||||||
|
|
||||||
|
async def update(self, id, data) -> dict:
|
||||||
|
logging.info("{} Get Update".format(self.name))
|
||||||
|
await self.stop(id)
|
||||||
|
if self.autostart is True:
|
||||||
|
await self.start(id)
|
||||||
|
self.data = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.data))
|
||||||
|
await self.save()
|
||||||
|
return self.find_by_id(id)
|
||||||
|
|
||||||
|
async def delete(self, id) -> None:
|
||||||
|
logging.info("{} Delete".format(self.name))
|
||||||
|
await self.stop(id)
|
||||||
|
self.data = list(filter(lambda x: x["id"] != id, self.data))
|
||||||
|
await self.save()
|
||||||
|
|
||||||
|
async def call_action(self, id, action, parameter) -> None:
|
||||||
|
|
||||||
|
logging.info("{} call all Action {} {}".format(self.name, id, action))
|
||||||
|
try:
|
||||||
|
item = self.find_by_id(id)
|
||||||
|
print(item)
|
||||||
|
instance = item.get("instance")
|
||||||
|
await instance.__getattribute__(action)(**parameter)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("{} Faild to call action on {} {} {}".format(self.name, id, action, e))
|
|
@ -1,169 +0,0 @@
|
||||||
import pprint
|
|
||||||
from abc import ABCMeta
|
|
||||||
|
|
||||||
from cbpi.api import *
|
|
||||||
|
|
||||||
|
|
||||||
class CRUDController(metaclass=ABCMeta):
|
|
||||||
|
|
||||||
|
|
||||||
cache = {}
|
|
||||||
caching = True
|
|
||||||
name = None
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.cache = {}
|
|
||||||
|
|
||||||
async def init(self):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
if self.caching is True:
|
|
||||||
self.cache = await self.model.get_all()
|
|
||||||
|
|
||||||
async def get_all(self, force_db_update=False):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param force_db_update:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
if self.caching is False or force_db_update:
|
|
||||||
self.cache = await self.model.get_all()
|
|
||||||
|
|
||||||
return self.cache
|
|
||||||
|
|
||||||
async def get_one(self, id):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param id:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
if id not in self.cache:
|
|
||||||
raise CBPiException("%s with id %s not found" % (self.name,id))
|
|
||||||
return self.cache.get(id)
|
|
||||||
|
|
||||||
async def _pre_add_callback(self, data):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param data:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _post_add_callback(self, m):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param m:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def add(self, **data):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param data:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
await self._pre_add_callback(data)
|
|
||||||
|
|
||||||
|
|
||||||
m = await self.model.insert(**data)
|
|
||||||
|
|
||||||
self.cache[m.id] = m
|
|
||||||
await self._post_add_callback(m)
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/added" % m.id, actor=m)
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
async def _pre_update_callback(self, m):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _post_update_callback(self, m):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def update(self, id, data):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param id:
|
|
||||||
:param data:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
self.logger.debug("Update Sensor %s - %s " % (id, data))
|
|
||||||
|
|
||||||
id = int(id)
|
|
||||||
|
|
||||||
if self.caching is True and id not in self.cache:
|
|
||||||
|
|
||||||
self.logger.debug("%s %s Not in Cache" % (self.name, id))
|
|
||||||
raise CBPiException("%s with id %s not found" % (self.name,id))
|
|
||||||
|
|
||||||
data["id"] = id
|
|
||||||
|
|
||||||
try:
|
|
||||||
### DELETE INSTANCE BEFORE UPDATE
|
|
||||||
del data["instance"]
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.caching is True:
|
|
||||||
await self._pre_update_callback(self.cache[id])
|
|
||||||
self.cache[id].__dict__.update(**data)
|
|
||||||
m = self.cache[id] = await self.model.update(**self.cache[id].__dict__)
|
|
||||||
await self._post_update_callback(self.cache[id])
|
|
||||||
else:
|
|
||||||
m = await self.model.update(**data)
|
|
||||||
return m
|
|
||||||
|
|
||||||
async def _pre_delete_callback(self, m):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param m:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _post_delete_callback(self, id):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param id:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def delete(self, id):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param id:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
|
|
||||||
if id not in self.cache:
|
|
||||||
raise CBPiException("%s with id %s not found" % (self.name,id))
|
|
||||||
|
|
||||||
await self._pre_delete_callback(id)
|
|
||||||
m = await self.model.delete(id)
|
|
||||||
await self._post_delete_callback(id)
|
|
||||||
try:
|
|
||||||
if self.caching is True:
|
|
||||||
del self.cache[int(id)]
|
|
||||||
except Exception as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/deleted" % id, id=id)
|
|
||||||
|
|
||||||
async def delete_all(self):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
self.model.delete_all()
|
|
||||||
if self.caching is True:
|
|
||||||
self.cache = {}
|
|
||||||
#self.cbpi.push_ws("DELETE_ALL_%s" % self.key, None)
|
|
|
@ -1,23 +1,18 @@
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
|
||||||
from cbpi.database.model import DashboardModel, DashboardContentModel
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
class DashboardController(CRUDController):
|
class DashboardController():
|
||||||
|
|
||||||
model = DashboardModel
|
|
||||||
name = "Dashboard"
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.caching = False
|
self.caching = False
|
||||||
super(DashboardController, self).__init__(cbpi)
|
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.cbpi.register(self)
|
self.cbpi.register(self)
|
||||||
|
|
||||||
def get_state(self):
|
async def init(self):
|
||||||
return dict(items=self.cache)
|
pass
|
||||||
|
|
||||||
async def get_content(self, dashboard_id):
|
async def get_content(self, dashboard_id):
|
||||||
try:
|
try:
|
||||||
|
@ -27,11 +22,9 @@ class DashboardController(CRUDController):
|
||||||
except:
|
except:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
async def add_content(self, dashboard_id, data):
|
async def add_content(self, dashboard_id, data):
|
||||||
with open('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id, 'w') as outfile:
|
with open('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id, 'w') as outfile:
|
||||||
json.dump(data, outfile, indent=4, sort_keys=True)
|
json.dump(data, outfile, indent=4, sort_keys=True)
|
||||||
|
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
async def delete_content(self, dashboard_id):
|
async def delete_content(self, dashboard_id):
|
||||||
|
|
|
@ -1,179 +1,41 @@
|
||||||
import re
|
from cbpi.controller.basic_controller import BasicController
|
||||||
from cbpi.api import *
|
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
|
||||||
from cbpi.database.model import KettleModel
|
|
||||||
from cbpi.job.aiohttp import get_scheduler_from_app
|
|
||||||
import logging
|
import logging
|
||||||
|
from tabulate import tabulate
|
||||||
class KettleController(CRUDController):
|
class KettleController(BasicController):
|
||||||
'''
|
|
||||||
The main kettle controller
|
|
||||||
'''
|
|
||||||
model = KettleModel
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super(KettleController, self).__init__(cbpi)
|
super(KettleController, self).__init__(cbpi, "kettle.json")
|
||||||
self.cbpi = cbpi
|
self.autostart = False
|
||||||
self.types = {}
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.cbpi.register(self)
|
|
||||||
|
|
||||||
async def init(self):
|
async def on(self, id):
|
||||||
'''
|
try:
|
||||||
This method initializes all actors during startup. It creates actor instances
|
item = self.find_by_id(id)
|
||||||
|
instance = item.get("instance")
|
||||||
|
await instance.start()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild to switch on KettleLogic {} {}".format(id, e))
|
||||||
|
|
||||||
:return:
|
async def off(self, id):
|
||||||
'''
|
try:
|
||||||
await super(KettleController, self).init()
|
item = self.find_by_id(id)
|
||||||
for key, value in self.cache.items():
|
instance = item.get("instance")
|
||||||
value.state = False
|
await instance.stop()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild to switch on KettleLogic {} {}".format(id, e))
|
||||||
|
|
||||||
|
async def set_target_temp(self, id, target_temp):
|
||||||
|
try:
|
||||||
|
item = self.find_by_id(id)
|
||||||
|
item["target_temp"] = target_temp
|
||||||
|
await self.save()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("Faild to set Target Temp {} {}".format(id, e))
|
||||||
|
|
||||||
def get_state(self):
|
def create_dict(self, data):
|
||||||
return dict(items=self.cache,types=self.types)
|
try:
|
||||||
|
instance = data.get("instance")
|
||||||
async def toggle_automtic(self, id):
|
state = dict(state=instance.get_state())
|
||||||
'''
|
except Exception as e:
|
||||||
|
logging.error("Faild to create KettleLogic dict {} ".format(e))
|
||||||
Convenience Method to toggle automatic
|
state = dict()
|
||||||
|
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), sensor=data.get("sensor"), heater=data.get("heater"), agitator=data.get("agitator"), target_temp=data.get("target_temp"), state=state,props=data.get("props", []))
|
||||||
:param id: kettle id as int
|
|
||||||
:return: (boolean, string)
|
|
||||||
'''
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle not found")
|
|
||||||
if kettle.logic is None:
|
|
||||||
raise CBPiExtension("Logic not found for kettle id: %s" % id)
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="kettle/%s/automatic" % id, id=id)
|
|
||||||
|
|
||||||
@on_event(topic="job/+/done")
|
|
||||||
async def job_stop(self, key, **kwargs) -> None:
|
|
||||||
|
|
||||||
match = re.match("kettle_logic_(\d+)", key)
|
|
||||||
if match is not None:
|
|
||||||
kid = match.group(1)
|
|
||||||
|
|
||||||
|
|
||||||
kettle = self.cache[int(kid)]
|
|
||||||
kettle.instance = None
|
|
||||||
kettle.state = False
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="kettle/%s/logic/stop" % kid)
|
|
||||||
|
|
||||||
@on_event(topic="kettle/+/automatic")
|
|
||||||
async def handle_automtic_event(self, id, **kwargs):
|
|
||||||
|
|
||||||
'''
|
|
||||||
Method to handle the event 'kettle/+/automatic'
|
|
||||||
|
|
||||||
:param id: The kettle id
|
|
||||||
:param kwargs:
|
|
||||||
:return: None
|
|
||||||
'''
|
|
||||||
id = int(id)
|
|
||||||
|
|
||||||
|
|
||||||
if id in self.cache:
|
|
||||||
|
|
||||||
kettle = self.cache[id]
|
|
||||||
|
|
||||||
if hasattr(kettle, "instance") is False:
|
|
||||||
kettle.instance = None
|
|
||||||
self._is_logic_running(id)
|
|
||||||
|
|
||||||
|
|
||||||
if kettle.instance is None:
|
|
||||||
|
|
||||||
if kettle.logic in self.types:
|
|
||||||
clazz = self.types.get("CustomKettleLogic")["class"]
|
|
||||||
cfg = kettle.config.copy()
|
|
||||||
cfg.update(dict(cbpi=self.cbpi))
|
|
||||||
kettle.instance = clazz(**cfg)
|
|
||||||
|
|
||||||
await self.cbpi.job.start_job(kettle.instance.run(), "kettle_logic_%s" % kettle.id, "kettle_logic%s" % id)
|
|
||||||
kettle.state = True
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="kettle/%s/logic/start" % id)
|
|
||||||
else:
|
|
||||||
kettle.instance.running = False
|
|
||||||
kettle.instance = None
|
|
||||||
kettle.state = False
|
|
||||||
await self.cbpi.bus.fire(topic="kettle/%s/logic/stop" % id)
|
|
||||||
|
|
||||||
def _is_logic_running(self, kettle_id):
|
|
||||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
|
||||||
|
|
||||||
async def heater_on(self, id):
|
|
||||||
'''
|
|
||||||
Convenience Method to switch the heater of a kettle on
|
|
||||||
:param id: the kettle id
|
|
||||||
:return: (boolean, string)
|
|
||||||
'''
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle not found")
|
|
||||||
if kettle.sensor is None:
|
|
||||||
raise ActorException("Actor not defined for kettle id %s" % id)
|
|
||||||
heater_id = kettle.heater
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/switch/on" % heater_id, actor_id=heater_id, power=99)
|
|
||||||
|
|
||||||
async def heater_off(self, id):
|
|
||||||
'''
|
|
||||||
|
|
||||||
Convenience Method to switch the heater of a kettle off
|
|
||||||
|
|
||||||
:param id:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle not found")
|
|
||||||
if kettle.sensor is None:
|
|
||||||
raise ActorException("Actor not defined for kettle id %s" % id)
|
|
||||||
heater_id = kettle.heater
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/switch/off" % heater_id, actor_id=heater_id, power=99)
|
|
||||||
|
|
||||||
async def agitator_on(self, id):
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle not found")
|
|
||||||
if kettle.sensor is None:
|
|
||||||
raise ActorException("Actor not defined for kettle id %s" % id)
|
|
||||||
agitator_id = kettle.agitator
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/switch/on" % agitator_id, actor_id=agitator_id, power=99)
|
|
||||||
|
|
||||||
async def agitator_off(self, id):
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle not found")
|
|
||||||
if kettle.sensor is None:
|
|
||||||
raise ActorException("Actor not defined for kettle id %s" % id)
|
|
||||||
agitator_id = kettle.agitator
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/switch/off" % agitator_id, actor_id=agitator_id, power=99)
|
|
||||||
|
|
||||||
async def get_traget_temp(self, id):
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle Not Found")
|
|
||||||
return kettle.target_temp
|
|
||||||
|
|
||||||
async def get_temp(self, id):
|
|
||||||
|
|
||||||
kettle = await self.get_one(id)
|
|
||||||
if kettle is None:
|
|
||||||
raise KettleException("Kettle Not Found")
|
|
||||||
if kettle.sensor is None:
|
|
||||||
raise SensorException("Sensor not defined for kettle id %s" % id)
|
|
||||||
|
|
||||||
sensor_id = kettle.sensor
|
|
||||||
return await self.cbpi.sensor.get_value(sensor_id)
|
|
||||||
|
|
||||||
@on_event(topic="kettle/+/targettemp")
|
|
||||||
async def set_target_temp(self, kettle_id, target_temp, **kwargs) -> None:
|
|
||||||
|
|
||||||
kettle = self.cache[int(kettle_id)]
|
|
||||||
kettle.target_temp = int(target_temp)
|
|
||||||
await self.model.update(**kettle.__dict__)
|
|
||||||
await self.cbpi.bus.fire("kettle/%s/targettemp/set" % kettle_id)
|
|
|
@ -7,7 +7,6 @@ from time import strftime, localtime
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
class LogController:
|
class LogController:
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
|
|
|
@ -18,9 +18,10 @@ class PluginController():
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
|
|
||||||
self.plugins = {}
|
|
||||||
self.plugins = load_config("./config/plugin_list.txt")
|
self.plugins = load_config("./config/plugin_list.txt")
|
||||||
|
if self.plugins is None:
|
||||||
|
self.plugins = {}
|
||||||
|
|
||||||
|
|
||||||
async def load_plugin_list(self):
|
async def load_plugin_list(self):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
|
@ -98,7 +99,7 @@ class PluginController():
|
||||||
self.modules[filename] = import_module(
|
self.modules[filename] = import_module(
|
||||||
"cbpi.extension.%s" % (filename))
|
"cbpi.extension.%s" % (filename))
|
||||||
self.modules[filename].setup(self.cbpi)
|
self.modules[filename].setup(self.cbpi)
|
||||||
logger.info("Plugin %s loaded successful" % filename)
|
#logger.info("Plugin %s loaded successful" % filename)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Plugin %s is not supporting version 4" % filename)
|
"Plugin %s is not supporting version 4" % filename)
|
||||||
|
@ -116,7 +117,7 @@ class PluginController():
|
||||||
self.modules[p] = import_module(p)
|
self.modules[p] = import_module(p)
|
||||||
self.modules[p].setup(self.cbpi)
|
self.modules[p].setup(self.cbpi)
|
||||||
|
|
||||||
logger.info("Plugin %s loaded successfully" % p)
|
#logger.info("Plugin %s loaded successfully" % p)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("FAILED to load plugin %s " % p)
|
logger.error("FAILED to load plugin %s " % p)
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
@ -128,22 +129,19 @@ class PluginController():
|
||||||
:param clazz: actor class
|
:param clazz: actor class
|
||||||
:return: None
|
:return: None
|
||||||
'''
|
'''
|
||||||
logger.info("Register %s Class %s" % (name, clazz.__name__))
|
logger.debug("Register %s Class %s" % (name, clazz.__name__))
|
||||||
if issubclass(clazz, CBPiActor):
|
|
||||||
# self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
|
|
||||||
self.cbpi.actor.types[name] = self._parse_props(clazz)
|
|
||||||
|
|
||||||
if issubclass(clazz, CBPiSensor):
|
if issubclass(clazz, CBPiActor2):
|
||||||
self.cbpi.sensor.types[name] = self._parse_props(clazz)
|
self.cbpi.actor.types[name] = self._parse_step_props(clazz,name)
|
||||||
|
|
||||||
if issubclass(clazz, CBPiKettleLogic):
|
if issubclass(clazz, CBPiKettleLogic2):
|
||||||
self.cbpi.kettle.types[name] = self._parse_props(clazz)
|
self.cbpi.kettle.types[name] = self._parse_step_props(clazz,name)
|
||||||
|
|
||||||
if issubclass(clazz, CBPiSimpleStep):
|
if issubclass(clazz, CBPiSensor2):
|
||||||
self.cbpi.step.types[name] = self._parse_props(clazz)
|
self.cbpi.sensor.types[name] = self._parse_step_props(clazz,name)
|
||||||
|
|
||||||
if issubclass(clazz, CBPiStep):
|
if issubclass(clazz, CBPiStep):
|
||||||
self.cbpi.step2.types[name] = self._parse_step_props(clazz,name)
|
self.cbpi.step.types[name] = self._parse_step_props(clazz,name)
|
||||||
|
|
||||||
if issubclass(clazz, CBPiExtension):
|
if issubclass(clazz, CBPiExtension):
|
||||||
self.c = clazz(self.cbpi)
|
self.c = clazz(self.cbpi)
|
||||||
|
@ -165,8 +163,7 @@ class PluginController():
|
||||||
|
|
||||||
def _parse_step_props(self, cls, name):
|
def _parse_step_props(self, cls, name):
|
||||||
|
|
||||||
result = {"name": name, "class": cls,
|
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
||||||
"properties": [], "actions": []}
|
|
||||||
|
|
||||||
if hasattr(cls, "cbpi_parameters"):
|
if hasattr(cls, "cbpi_parameters"):
|
||||||
parameters = []
|
parameters = []
|
||||||
|
@ -174,7 +171,9 @@ class PluginController():
|
||||||
parameters.append(self._parse_property_object(p))
|
parameters.append(self._parse_property_object(p))
|
||||||
result["properties"] = parameters
|
result["properties"] = parameters
|
||||||
for method_name, method in cls.__dict__.items():
|
for method_name, method in cls.__dict__.items():
|
||||||
|
|
||||||
if hasattr(method, "action"):
|
if hasattr(method, "action"):
|
||||||
|
print(method_name)
|
||||||
key = method.__getattribute__("key")
|
key = method.__getattribute__("key")
|
||||||
parameters = []
|
parameters = []
|
||||||
for p in method.__getattribute__("parameters"):
|
for p in method.__getattribute__("parameters"):
|
||||||
|
|
|
@ -1,84 +1,5 @@
|
||||||
|
from cbpi.controller.basic_controller import BasicController
|
||||||
|
|
||||||
import logging
|
class SensorController(BasicController):
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
|
||||||
from cbpi.database.model import SensorModel
|
|
||||||
from cbpi.job.aiohttp import get_scheduler_from_app
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SensorController(CRUDController):
|
|
||||||
|
|
||||||
model = SensorModel
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.cbpi = cbpi
|
super(SensorController, self).__init__(cbpi, "sensor.json")
|
||||||
self.cbpi.register(self)
|
|
||||||
self.service = self
|
|
||||||
self.types = {}
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.sensors = {}
|
|
||||||
|
|
||||||
async def init(self):
|
|
||||||
'''
|
|
||||||
This method initializes all actors during startup. It creates actor instances
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
await super(SensorController, self).init()
|
|
||||||
for id, value in self.cache.items():
|
|
||||||
await self.init_sensor(value)
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return dict(items=self.cache,types=self.types)
|
|
||||||
|
|
||||||
async def init_sensor(self, sensor):
|
|
||||||
|
|
||||||
|
|
||||||
print("INIT SENSOR")
|
|
||||||
if sensor.type in self.types:
|
|
||||||
cfg = sensor.config.copy()
|
|
||||||
cfg.update(dict(cbpi=self.cbpi, id=sensor.id, name=sensor.name))
|
|
||||||
clazz = self.types[sensor.type]["class"];
|
|
||||||
self.cache[sensor.id].instance = clazz(**cfg)
|
|
||||||
self.cache[sensor.id].instance.init()
|
|
||||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
|
||||||
|
|
||||||
self.cache[sensor.id].instance.job = await self.cbpi.job.start_job(self.cache[sensor.id].instance.run(self.cbpi), sensor.name, "sensor")
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="sensor/%s/initialized" % sensor.id, id=sensor.id)
|
|
||||||
else:
|
|
||||||
self.logger.error("Sensor type '%s' not found (Available Sensor Types: %s)" % (sensor.type, ', '.join(self.types.keys())))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def stop_sensor(self, sensor):
|
|
||||||
|
|
||||||
sensor.instance.stop()
|
|
||||||
await self.cbpi.bus.fire(topic="sensor/%s/stopped" % sensor.id, id=sensor.id)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_value(self, sensor_id):
|
|
||||||
sensor_id = int(sensor_id)
|
|
||||||
return self.cache[sensor_id].instance.value
|
|
||||||
|
|
||||||
async def _post_add_callback(self, m):
|
|
||||||
'''
|
|
||||||
|
|
||||||
:param m:
|
|
||||||
:return:
|
|
||||||
'''
|
|
||||||
await self.init_sensor(m)
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _pre_delete_callback(self, sensor_id):
|
|
||||||
if int(sensor_id) not in self.cache:
|
|
||||||
return
|
|
||||||
if hasattr(self.cache[int(sensor_id)], "instance") and self.cache[int(sensor_id)].instance is not None:
|
|
||||||
await self.stop_sensor(self.cache[int(sensor_id)])
|
|
||||||
|
|
||||||
async def _pre_update_callback(self, sensor):
|
|
||||||
|
|
||||||
if hasattr(sensor, "instance") and sensor.instance is not None:
|
|
||||||
await self.stop_sensor(sensor)
|
|
||||||
|
|
||||||
async def _post_update_callback(self, sensor):
|
|
||||||
await self.init_sensor(sensor)
|
|
||||||
|
|
|
@ -1,194 +1,245 @@
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from tabulate import tabulate
|
||||||
|
import json
|
||||||
|
import copy
|
||||||
|
import shortuuid
|
||||||
import logging
|
import logging
|
||||||
import time
|
import os.path
|
||||||
|
|
||||||
from cbpi.api import *
|
from ..api.step import CBPiStep
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
|
||||||
from cbpi.database.model import StepModel
|
|
||||||
|
|
||||||
|
|
||||||
class StepController(CRUDController):
|
|
||||||
|
|
||||||
|
|
||||||
|
class StepController:
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
self.model = StepModel
|
|
||||||
|
|
||||||
self.caching = True
|
|
||||||
self.is_stopping = False
|
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
self.current_task = None
|
self.woohoo = "HALLLO"
|
||||||
self.is_next = False
|
|
||||||
self.types = {}
|
|
||||||
self.current_step = None
|
|
||||||
self.current_job = None
|
|
||||||
self.cbpi.register(self)
|
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.starttime = None
|
self.path = os.path.join(".", 'config', "step_data.json")
|
||||||
|
self._loop = asyncio.get_event_loop()
|
||||||
|
self.basic_data = {}
|
||||||
|
self.step = None
|
||||||
|
self.types = {}
|
||||||
|
|
||||||
def is_running(self):
|
self.cbpi.app.on_cleanup.append(self.shutdown)
|
||||||
if self.current_step is not None:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _get_manged_fields_as_array(self, type_cfg):
|
|
||||||
|
|
||||||
result = []
|
|
||||||
|
|
||||||
for f in type_cfg.get("properties"):
|
|
||||||
|
|
||||||
result.append(f.get("name"))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
|
logging.info("INIT STEP Controller")
|
||||||
|
self.load(startActive=True)
|
||||||
|
|
||||||
# load all steps into cache
|
def load(self, startActive=False):
|
||||||
self.cache = await self.model.get_all()
|
|
||||||
|
|
||||||
|
# create file if not exists
|
||||||
|
if os.path.exists(self.path) is False:
|
||||||
|
with open(self.path, "w") as file:
|
||||||
|
json.dump(dict(basic={}, profile=[]), file, indent=4, sort_keys=True)
|
||||||
|
|
||||||
for key, value in self.cache.items():
|
#load from json file
|
||||||
|
with open(self.path) as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
self.basic_data = data["basic"]
|
||||||
|
self.profile = data["profile"]
|
||||||
|
|
||||||
# get step type as string
|
# Start step after start up
|
||||||
step_type = self.types.get(value.type)
|
self.profile = list(map(lambda item: {**item, "instance": self.create_step(item.get("id"), item.get("type"), item.get("name"), item.get("props", {}))}, self.profile))
|
||||||
|
if startActive is True:
|
||||||
|
active_step = self.find_by_status("A")
|
||||||
|
if active_step is not None:
|
||||||
|
self._loop.create_task(self.start_step(active_step))
|
||||||
|
|
||||||
# if step has state
|
async def add(self, data):
|
||||||
if value.stepstate is not None:
|
logging.info("Add step")
|
||||||
cfg = value.stepstate.copy()
|
id = shortuuid.uuid()
|
||||||
else:
|
item = {**{"status": "I", "props": {}}, **data, "id": id, "instance": self.create_step(id, data.get("type"), data.get("name"), data.get("props", {}))}
|
||||||
cfg = {}
|
self.profile.append(item)
|
||||||
|
await self.save()
|
||||||
|
return item
|
||||||
|
|
||||||
# set managed fields
|
async def update(self, id, data):
|
||||||
cfg.update(dict(cbpi=self.cbpi, id=value.id, managed_fields=self._get_manged_fields_as_array(step_type)))
|
logging.info("update step")
|
||||||
|
|
||||||
if value.config is not None:
|
self.profile = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.profile))
|
||||||
# set config values
|
await self.save()
|
||||||
cfg.update(**value.config)
|
return self.find_by_id(id)
|
||||||
# create step instance
|
|
||||||
value.instance = step_type["class"](**cfg)
|
|
||||||
|
|
||||||
async def get_all(self, force_db_update: bool = True):
|
async def save(self):
|
||||||
return self.cache
|
logging.debug("save profile")
|
||||||
|
data = dict(basic=self.basic_data, profile=list(map(lambda x: dict(name=x["name"], type=x.get("type"), id=x["id"], status=x["status"],props=x["props"]), self.profile)))
|
||||||
|
with open(self.path, "w") as file:
|
||||||
|
json.dump(data, file, indent=4, sort_keys=True)
|
||||||
|
await self.push_udpate()
|
||||||
|
|
||||||
def find_next_step(self):
|
async def start(self):
|
||||||
# filter
|
# already running
|
||||||
inactive_steps = {k: v for k, v in self.cache.items() if v.state == 'I'}
|
if self.find_by_status("A") is not None:
|
||||||
if len(inactive_steps) == 0:
|
logging.error("Steps already running")
|
||||||
return None
|
|
||||||
return min(inactive_steps, key=lambda x: inactive_steps[x].order)
|
|
||||||
|
|
||||||
@on_event("step/start")
|
|
||||||
async def start(self, **kwargs):
|
|
||||||
|
|
||||||
if self.is_running() is False:
|
|
||||||
next_step_id = self.find_next_step()
|
|
||||||
if next_step_id:
|
|
||||||
next_step = self.cache[next_step_id]
|
|
||||||
next_step.state = 'A'
|
|
||||||
next_step.stepstate = next_step.config
|
|
||||||
next_step.start = int(time.time())
|
|
||||||
await self.model.update(**next_step.__dict__)
|
|
||||||
self.current_step = next_step
|
|
||||||
# start the step job
|
|
||||||
self.current_job = await self.cbpi.job.start_job(self.current_step.instance.run(), next_step.name, "step")
|
|
||||||
await self.cbpi.bus.fire("step/%s/started" % self.current_step.id, step=next_step)
|
|
||||||
else:
|
|
||||||
await self.cbpi.bus.fire("step/brewing/finished")
|
|
||||||
else:
|
|
||||||
self.logger.error("Process Already Running")
|
|
||||||
|
|
||||||
async def next(self, **kwargs):
|
|
||||||
|
|
||||||
if self.current_step is not None:
|
|
||||||
|
|
||||||
self.is_next = True
|
|
||||||
self.current_step.instance.stop()
|
|
||||||
|
|
||||||
@on_event("job/step/done")
|
|
||||||
async def step_done(self, **kwargs):
|
|
||||||
|
|
||||||
if self.cbpi.shutdown:
|
|
||||||
return
|
return
|
||||||
if self.is_stopping:
|
# Find next inactive step
|
||||||
self.is_stopping = False
|
step = self.find_by_status("P")
|
||||||
|
if step is not None:
|
||||||
|
|
||||||
|
logging.info("Resume step")
|
||||||
|
|
||||||
|
await self.start_step(step)
|
||||||
|
await self.save()
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.current_step is not None:
|
step = self.find_by_status("I")
|
||||||
|
if step is not None:
|
||||||
|
logging.info("Start Step")
|
||||||
|
|
||||||
self.current_step.state = "D"
|
await self.start_step(step)
|
||||||
await self.model.update_state(self.current_step.id, "D", int(time.time()))
|
await self.save()
|
||||||
await self.cbpi.bus.fire("step/%s/done" % self.current_step.id, step=self.current_step)
|
return
|
||||||
self.current_step = None
|
|
||||||
|
|
||||||
# start the next step
|
logging.info("BREWING COMPLETE")
|
||||||
|
|
||||||
|
async def next(self):
|
||||||
|
logging.info("Trigger Next")
|
||||||
|
step = self.find_by_status("A")
|
||||||
|
if step is not None:
|
||||||
|
instance = step.get("instance")
|
||||||
|
if instance is not None:
|
||||||
|
logging.info("Next")
|
||||||
|
instance.next()
|
||||||
|
await instance.task
|
||||||
|
else:
|
||||||
|
logging.info("No Step is running")
|
||||||
|
|
||||||
|
async def resume(self):
|
||||||
|
step = self.find_by_status("P")
|
||||||
|
if step is not None:
|
||||||
|
instance = step.get("instance")
|
||||||
|
if instance is not None:
|
||||||
|
await self.start_step(step)
|
||||||
|
else:
|
||||||
|
logging.info("Nothing to resume")
|
||||||
|
|
||||||
|
async def stop(self):
|
||||||
|
logging.info("STOP STEP")
|
||||||
|
step = self.find_by_status("A")
|
||||||
|
if step != None and step.get("instance") is not None:
|
||||||
|
logging.info("CALLING STOP STEP")
|
||||||
|
instance = step.get("instance")
|
||||||
|
instance.stop()
|
||||||
|
# wait for task to be finished
|
||||||
|
await instance.task
|
||||||
|
logging.info("STEP STOPPED")
|
||||||
|
step["status"] = "P"
|
||||||
|
await self.save()
|
||||||
|
|
||||||
|
async def reset_all(self):
|
||||||
|
step = self.find_by_status("A")
|
||||||
|
if step is not None:
|
||||||
|
logging.error("Please stop before reset")
|
||||||
|
return
|
||||||
|
for item in self.profile:
|
||||||
|
logging.info("Reset %s" % item.get("name"))
|
||||||
|
item["status"] = "I"
|
||||||
|
await item["instance"].reset()
|
||||||
|
await self.push_udpate()
|
||||||
|
|
||||||
|
def create_step(self, id, type, name, props):
|
||||||
|
|
||||||
|
try:
|
||||||
|
type_cfg = self.types.get(type)
|
||||||
|
clazz = type_cfg.get("class")
|
||||||
|
return clazz(self.cbpi, id, name, {**props})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_dict(self, data):
|
||||||
|
return dict(name=data["name"], id=data["id"], type=data.get("type"), status=data["status"],props=data["props"], state_text=data["instance"].get_state())
|
||||||
|
|
||||||
|
def get_types2(self):
|
||||||
|
result = {}
|
||||||
|
for key, value in self.types.items():
|
||||||
|
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return {"basic": self.basic_data, "profile": list(map(lambda x: self.create_dict(x), self.profile)), "types":self.get_types2()}
|
||||||
|
|
||||||
|
async def move(self, id, direction):
|
||||||
|
index = self.get_index_by_id(id)
|
||||||
|
if direction not in [-1, 1]:
|
||||||
|
self.logger.error("Cant move. Direction 1 and -1 allowed")
|
||||||
|
return
|
||||||
|
self.profile[index], self.profile[index+direction] = self.profile[index+direction], self.profile[index]
|
||||||
|
await self.save()
|
||||||
|
await self.push_udpate()
|
||||||
|
|
||||||
|
async def delete(self, id):
|
||||||
|
step = self.find_by_id(id)
|
||||||
|
if step.get("status") == "A":
|
||||||
|
logging.error("Cant delete active Step %s", id)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.profile = list(filter(lambda x: x["id"] != id, self.profile))
|
||||||
|
await self.save()
|
||||||
|
|
||||||
|
|
||||||
|
async def shutdown(self, app):
|
||||||
|
logging.info("Mash Profile Shutdonw")
|
||||||
|
for p in self.profile:
|
||||||
|
instance = p.get("instance")
|
||||||
|
# Stopping all running task
|
||||||
|
if instance.task != None and instance.task.done() is False:
|
||||||
|
logging.info("Stop Step")
|
||||||
|
instance.stop()
|
||||||
|
await instance.task
|
||||||
|
await self.save()
|
||||||
|
|
||||||
|
def done(self, task):
|
||||||
|
id, reason = task.result()
|
||||||
|
if reason == "MAX_EXCEPTIONS":
|
||||||
|
step_current = self.find_by_id(id)
|
||||||
|
step_current["status"] = "E"
|
||||||
|
self._loop.create_task(self.save())
|
||||||
|
return
|
||||||
|
|
||||||
|
if reason == "NEXT":
|
||||||
|
step_current = self.find_by_status("A")
|
||||||
|
if step_current is not None:
|
||||||
|
|
||||||
|
step_current["status"] = "D"
|
||||||
|
async def wrapper():
|
||||||
|
## TODO DONT CALL SAVE
|
||||||
|
await self.save()
|
||||||
await self.start()
|
await self.start()
|
||||||
|
self._loop.create_task(wrapper())
|
||||||
|
|
||||||
@on_event("step/stop")
|
|
||||||
async def stop_all(self, **kwargs):
|
|
||||||
# RESET DB
|
|
||||||
await self.model.reset_all_steps()
|
|
||||||
# RELOAD all Steps from DB into cache and initialize Instances
|
|
||||||
await self.init()
|
|
||||||
await self.cbpi.bus.fire("step/brewing/stopped")
|
|
||||||
|
|
||||||
@on_event("step/clear")
|
def find_by_status(self, status):
|
||||||
async def clear_all(self, **kwargs):
|
return next((item for item in self.profile if item["status"] == status), None)
|
||||||
await self.model.delete_all()
|
|
||||||
self.cbpi.notify(key="Steps Cleared", message="Steps cleared successfully", type="success")
|
|
||||||
|
|
||||||
async def _pre_add_callback(self, data):
|
def find_by_id(self, id):
|
||||||
|
return next((item for item in self.profile if item["id"] == id), None)
|
||||||
|
|
||||||
order = await self.model.get_max_order()
|
def get_index_by_id(self, id):
|
||||||
data["order"] = 1 if order is None else order + 1
|
return next((i for i, item in enumerate(self.profile) if item["id"] == id), None)
|
||||||
data["state"] = "I"
|
|
||||||
data["stepstate"] = {}
|
|
||||||
return await super()._pre_add_callback(data)
|
|
||||||
|
|
||||||
async def init_step(self, value: StepModel):
|
async def push_udpate(self):
|
||||||
step_type = self.types.get(value.type)
|
await self.cbpi.bus.fire("step/update", data=list(map(lambda x: self.create_dict(x), self.profile)))
|
||||||
|
|
||||||
# if step has state
|
async def start_step(self,step):
|
||||||
if value.stepstate is not None:
|
logging.info("Start Step")
|
||||||
cfg = value.stepstate.copy()
|
step.get("instance").start()
|
||||||
else:
|
step["instance"].task = self._loop.create_task(step["instance"].run(), name=step["name"])
|
||||||
cfg = {}
|
step["instance"].task .add_done_callback(self.done)
|
||||||
|
step["status"] = "A"
|
||||||
|
|
||||||
# set managed fields
|
async def update_props(self, id, props):
|
||||||
cfg.update(dict(cbpi=self.cbpi, id=value.id, managed_fields=self._get_manged_fields_as_array(step_type)))
|
logging.info("SAVE PROPS")
|
||||||
# set config values
|
step = self.find_by_id(id)
|
||||||
cfg.update(**value.config)
|
step["props"] = props
|
||||||
# create step instance
|
await self.save()
|
||||||
value.instance = step_type["class"](**cfg)
|
await self.push_udpate()
|
||||||
return value
|
|
||||||
|
|
||||||
async def _post_add_callback(self, m: StepModel) -> None:
|
async def save_basic(self, data):
|
||||||
self.cache[m.id] = await self.init_step(m)
|
logging.info("SAVE Basic Data")
|
||||||
|
self.basic_data = {**self.basic_data, **data,}
|
||||||
async def _post_update_callback(self, m: StepModel) -> None:
|
await self.save()
|
||||||
'''
|
await self.push_udpate()
|
||||||
:param m: step model
|
|
||||||
:return: None
|
|
||||||
'''
|
|
||||||
self.cache[m.id] = await self.init_step(m)
|
|
||||||
|
|
||||||
@on_event("step/sort")
|
|
||||||
async def sort(self, topic: 'str', data: 'dict', **kwargs):
|
|
||||||
|
|
||||||
# update order in cache
|
|
||||||
for id, order in data.items():
|
|
||||||
self.cache[int(id)].order = order
|
|
||||||
|
|
||||||
# update oder in database
|
|
||||||
await self.model.sort(data)
|
|
||||||
|
|
||||||
async def get_state(self):
|
|
||||||
return dict(items=await self.get_all(),types=self.types,is_running=self.is_running(),current_step=self.current_step)
|
|
||||||
|
|
||||||
@on_event(topic="step/action")
|
|
||||||
async def call_action(self, name, parameter, **kwargs) -> None:
|
|
||||||
print(name, parameter)
|
|
||||||
if self.current_step is not None:
|
|
||||||
|
|
||||||
self.current_step.instance.__getattribute__(name)(**parameter)
|
|
||||||
|
|
|
@ -1,251 +0,0 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from tabulate import tabulate
|
|
||||||
import json
|
|
||||||
import copy
|
|
||||||
import shortuuid
|
|
||||||
import logging
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
from ..api.step import CBPiStep
|
|
||||||
|
|
||||||
class Step2(CBPiStep):
|
|
||||||
|
|
||||||
async def execute(self):
|
|
||||||
|
|
||||||
print(self.props)
|
|
||||||
await self.update(self.props)
|
|
||||||
print("HALLO")
|
|
||||||
#raise Exception("RROR")
|
|
||||||
|
|
||||||
class StepControllerNg:
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.woohoo = "HALLLO"
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.path = os.path.join(".", 'config', "step_data.json")
|
|
||||||
self._loop = asyncio.get_event_loop()
|
|
||||||
self.basic_data = {}
|
|
||||||
self.step = None
|
|
||||||
self.types = {}
|
|
||||||
|
|
||||||
self.cbpi.app.on_cleanup.append(self.shutdown)
|
|
||||||
|
|
||||||
async def init(self):
|
|
||||||
logging.info("INIT STEP Controller")
|
|
||||||
self.load(startActive=True)
|
|
||||||
|
|
||||||
def load(self, startActive=False):
|
|
||||||
|
|
||||||
# create file if not exists
|
|
||||||
if os.path.exists(self.path) is False:
|
|
||||||
with open(self.path, "w") as file:
|
|
||||||
json.dump(dict(basic={}, profile=[]), file, indent=4, sort_keys=True)
|
|
||||||
|
|
||||||
#load from json file
|
|
||||||
with open(self.path) as json_file:
|
|
||||||
data = json.load(json_file)
|
|
||||||
self.basic_data = data["basic"]
|
|
||||||
self.profile = data["profile"]
|
|
||||||
|
|
||||||
# Start step after start up
|
|
||||||
self.profile = list(map(lambda item: {**item, "instance": self.create_step(item.get("id"), item.get("type"), item.get("name"), item.get("props", {}))}, self.profile))
|
|
||||||
if startActive is True:
|
|
||||||
active_step = self.find_by_status("A")
|
|
||||||
if active_step is not None:
|
|
||||||
self._loop.create_task(self.start_step(active_step))
|
|
||||||
|
|
||||||
async def add(self, data):
|
|
||||||
logging.info("Add step")
|
|
||||||
print(data)
|
|
||||||
id = shortuuid.uuid()
|
|
||||||
item = {**{"status": "I", "props": {}}, **data, "id": id, "instance": self.create_step(id, data.get("type"), data.get("name"), data.get("props", {}))}
|
|
||||||
self.profile.append(item)
|
|
||||||
await self.save()
|
|
||||||
return item
|
|
||||||
|
|
||||||
async def update(self, id, data):
|
|
||||||
logging.info("update step")
|
|
||||||
print(id, data)
|
|
||||||
#if "instance" in data: del data["instance"]
|
|
||||||
self.profile = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.profile))
|
|
||||||
print(tabulate(self.profile))
|
|
||||||
await self.save()
|
|
||||||
return self.find_by_id(id)
|
|
||||||
|
|
||||||
async def save(self):
|
|
||||||
logging.debug("save profile")
|
|
||||||
data = dict(basic=self.basic_data, profile=list(map(lambda x: dict(name=x["name"], type=x.get("type"), id=x["id"], status=x["status"],props=x["props"]), self.profile)))
|
|
||||||
with open(self.path, "w") as file:
|
|
||||||
json.dump(data, file, indent=4, sort_keys=True)
|
|
||||||
await self.push_udpate()
|
|
||||||
|
|
||||||
async def start(self):
|
|
||||||
# already running
|
|
||||||
if self.find_by_status("A") is not None:
|
|
||||||
logging.error("Steps already running")
|
|
||||||
return
|
|
||||||
# Find next inactive step
|
|
||||||
step = self.find_by_status("P")
|
|
||||||
if step is not None:
|
|
||||||
|
|
||||||
logging.info("Resume step")
|
|
||||||
|
|
||||||
await self.start_step(step)
|
|
||||||
await self.save()
|
|
||||||
return
|
|
||||||
|
|
||||||
step = self.find_by_status("I")
|
|
||||||
if step is not None:
|
|
||||||
logging.info("Start Step")
|
|
||||||
|
|
||||||
await self.start_step(step)
|
|
||||||
await self.save()
|
|
||||||
return
|
|
||||||
|
|
||||||
logging.info("BREWING COMPLETE")
|
|
||||||
|
|
||||||
async def next(self):
|
|
||||||
logging.info("Trigger Next")
|
|
||||||
step = self.find_by_status("A")
|
|
||||||
if step is not None:
|
|
||||||
instance = step.get("instance")
|
|
||||||
if instance is not None:
|
|
||||||
logging.info("Next")
|
|
||||||
instance.next()
|
|
||||||
await instance.task
|
|
||||||
else:
|
|
||||||
logging.info("No Step is running")
|
|
||||||
|
|
||||||
async def resume(self):
|
|
||||||
step = self.find_by_status("P")
|
|
||||||
if step is not None:
|
|
||||||
instance = step.get("instance")
|
|
||||||
if instance is not None:
|
|
||||||
await self.start_step(step)
|
|
||||||
else:
|
|
||||||
logging.info("Nothing to resume")
|
|
||||||
|
|
||||||
async def stop(self):
|
|
||||||
logging.info("STOP STEP")
|
|
||||||
step = self.find_by_status("A")
|
|
||||||
if step != None and step.get("instance") is not None:
|
|
||||||
logging.info("CALLING STOP STEP")
|
|
||||||
instance = step.get("instance")
|
|
||||||
instance.stop()
|
|
||||||
# wait for task to be finished
|
|
||||||
await instance.task
|
|
||||||
logging.info("STEP STOPPED")
|
|
||||||
step["status"] = "P"
|
|
||||||
await self.save()
|
|
||||||
|
|
||||||
async def reset_all(self):
|
|
||||||
step = self.find_by_status("A")
|
|
||||||
if step is not None:
|
|
||||||
logging.error("Please stop before reset")
|
|
||||||
return
|
|
||||||
for item in self.profile:
|
|
||||||
logging.info("Reset %s" % item.get("name"))
|
|
||||||
item["status"] = "I"
|
|
||||||
await item["instance"].reset()
|
|
||||||
await self.push_udpate()
|
|
||||||
|
|
||||||
def create_step(self, id, type, name, props):
|
|
||||||
|
|
||||||
type_cfg = self.types.get(type)
|
|
||||||
clazz = type_cfg.get("class")
|
|
||||||
return clazz(self.cbpi, id, name, {**props})
|
|
||||||
|
|
||||||
def create_dict(self, data):
|
|
||||||
return dict(name=data["name"], id=data["id"], type=data.get("type"), status=data["status"],props=data["props"], state_text=data["instance"].get_state())
|
|
||||||
|
|
||||||
def get_types2(self):
|
|
||||||
result = {}
|
|
||||||
for key, value in self.types.items():
|
|
||||||
print(value)
|
|
||||||
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_state(self):
|
|
||||||
return {"basic": self.basic_data, "profile": list(map(lambda x: self.create_dict(x), self.profile)), "types":self.get_types2()}
|
|
||||||
|
|
||||||
async def move(self, id, direction):
|
|
||||||
index = self.get_index_by_id(id)
|
|
||||||
if direction not in [-1, 1]:
|
|
||||||
self.logger.error("Cant move. Direction 1 and -1 allowed")
|
|
||||||
return
|
|
||||||
self.profile[index], self.profile[index+direction] = self.profile[index+direction], self.profile[index]
|
|
||||||
self.save()
|
|
||||||
await self.push_udpate()
|
|
||||||
|
|
||||||
async def delete(self, id):
|
|
||||||
step = self.find_by_id(id)
|
|
||||||
if step.get("status") == "A":
|
|
||||||
logging.error("Cant delete active Step %s", id)
|
|
||||||
return
|
|
||||||
|
|
||||||
self.profile = list(filter(lambda x: x["id"] != id, self.profile))
|
|
||||||
await self.save()
|
|
||||||
|
|
||||||
|
|
||||||
async def shutdown(self, app):
|
|
||||||
logging.info("Mash Profile Shutdonw")
|
|
||||||
for p in self.profile:
|
|
||||||
instance = p.get("instance")
|
|
||||||
# Stopping all running task
|
|
||||||
if instance.task != None and instance.task.done() is False:
|
|
||||||
logging.info("Stop Step")
|
|
||||||
instance.stop()
|
|
||||||
await instance.task
|
|
||||||
await self.save()
|
|
||||||
|
|
||||||
def done(self, task):
|
|
||||||
id, reason = task.result()
|
|
||||||
print(id, reason)
|
|
||||||
if reason == "MAX_EXCEPTIONS":
|
|
||||||
step_current = self.find_by_id(id)
|
|
||||||
step_current["status"] = "E"
|
|
||||||
self._loop.create_task(self.save())
|
|
||||||
return
|
|
||||||
|
|
||||||
if reason == "NEXT":
|
|
||||||
step_current = self.find_by_status("A")
|
|
||||||
if step_current is not None:
|
|
||||||
step_current["status"] = "D"
|
|
||||||
async def wrapper():
|
|
||||||
await self.save()
|
|
||||||
await self.start()
|
|
||||||
self._loop.create_task(wrapper())
|
|
||||||
|
|
||||||
|
|
||||||
def find_by_status(self, status):
|
|
||||||
return next((item for item in self.profile if item["status"] == status), None)
|
|
||||||
|
|
||||||
def find_by_id(self, id):
|
|
||||||
return next((item for item in self.profile if item["id"] == id), None)
|
|
||||||
|
|
||||||
def get_index_by_id(self, id):
|
|
||||||
return next((i for i, item in enumerate(self.profile) if item["id"] == id), None)
|
|
||||||
|
|
||||||
async def push_udpate(self):
|
|
||||||
print("PUS UPDATE")
|
|
||||||
await self.cbpi.bus.fire("step/update", data=list(map(lambda x: self.create_dict(x), self.profile)))
|
|
||||||
|
|
||||||
async def start_step(self,step):
|
|
||||||
logging.info("############# start step")
|
|
||||||
step.get("instance").start()
|
|
||||||
step["instance"].task = self._loop.create_task(step["instance"].run(), name=step["name"])
|
|
||||||
print(step["instance"].task)
|
|
||||||
step["instance"].task .add_done_callback(self.done)
|
|
||||||
step["status"] = "A"
|
|
||||||
|
|
||||||
async def update_props(self, id, props):
|
|
||||||
logging.info("SAVE PROPS")
|
|
||||||
print(id, props)
|
|
||||||
step = self.find_by_id(id)
|
|
||||||
step["props"] = props
|
|
||||||
await self.save()
|
|
||||||
await self.push_udpate()
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
import logging
|
|
||||||
|
|
||||||
from cbpi.database.model import TranslationModel
|
|
||||||
|
|
||||||
class TranslationController(object):
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self._cache = {}
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
async def init(self):
|
|
||||||
self._cache = await TranslationModel.get_all()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_all(self):
|
|
||||||
return self._cache
|
|
||||||
|
|
||||||
async def add_key(self, locale, key):
|
|
||||||
|
|
||||||
try:
|
|
||||||
if locale not in self._cache or key not in self._cache[locale]:
|
|
||||||
await TranslationModel.add_key(locale, key)
|
|
||||||
self._cache = await TranslationModel.get_all()
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error("Error during adding translation key %s - %s - %s" % (key, locale, str(e)))
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
from os import urandom
|
from os import urandom
|
||||||
import os
|
import os
|
||||||
|
from cbpi import __version__
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_auth import auth
|
from aiohttp_auth import auth
|
||||||
from aiohttp_session import session_middleware
|
from aiohttp_session import session_middleware
|
||||||
|
@ -19,8 +19,9 @@ from cbpi.controller.notification_controller import NotificationController
|
||||||
from cbpi.controller.plugin_controller import PluginController
|
from cbpi.controller.plugin_controller import PluginController
|
||||||
from cbpi.controller.sensor_controller import SensorController
|
from cbpi.controller.sensor_controller import SensorController
|
||||||
from cbpi.controller.step_controller import StepController
|
from cbpi.controller.step_controller import StepController
|
||||||
from cbpi.controller.step_controller_ng import StepControllerNg
|
|
||||||
from cbpi.controller.system_controller import SystemController
|
from cbpi.controller.system_controller import SystemController
|
||||||
|
|
||||||
from cbpi.controller.log_file_controller import LogController
|
from cbpi.controller.log_file_controller import LogController
|
||||||
from cbpi.database.model import DBModel
|
from cbpi.database.model import DBModel
|
||||||
from cbpi.eventbus import CBPiEventBus
|
from cbpi.eventbus import CBPiEventBus
|
||||||
|
@ -28,14 +29,14 @@ from cbpi.http_endpoints.http_login import Login
|
||||||
from cbpi.utils import *
|
from cbpi.utils import *
|
||||||
from cbpi.websocket import CBPiWebSocket
|
from cbpi.websocket import CBPiWebSocket
|
||||||
from cbpi.http_endpoints.http_actor import ActorHttpEndpoints
|
from cbpi.http_endpoints.http_actor import ActorHttpEndpoints
|
||||||
|
|
||||||
|
|
||||||
from cbpi.http_endpoints.http_config import ConfigHttpEndpoints
|
from cbpi.http_endpoints.http_config import ConfigHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_dashboard import DashBoardHttpEndpoints
|
from cbpi.http_endpoints.http_dashboard import DashBoardHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_kettle import KettleHttpEndpoints
|
from cbpi.http_endpoints.http_kettle import KettleHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_sensor import SensorHttpEndpoints
|
from cbpi.http_endpoints.http_sensor import SensorHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_step import StepHttpEndpoints
|
from cbpi.http_endpoints.http_step import StepHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_step2 import StepHttpEndpoints2
|
|
||||||
from cbpi.controller.translation_controller import TranslationController
|
|
||||||
from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
|
|
||||||
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_log import LogHttpEndpoints
|
from cbpi.http_endpoints.http_log import LogHttpEndpoints
|
||||||
|
@ -68,7 +69,7 @@ class CraftBeerPi():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.version = "4.0.0.1"
|
self.version = __version__
|
||||||
|
|
||||||
self.static_config = load_config("./config/config.yaml")
|
self.static_config = load_config("./config/config.yaml")
|
||||||
self.database_file = "./craftbeerpi.db"
|
self.database_file = "./craftbeerpi.db"
|
||||||
|
@ -87,26 +88,24 @@ class CraftBeerPi():
|
||||||
self.config = ConfigController(self)
|
self.config = ConfigController(self)
|
||||||
self.ws = CBPiWebSocket(self)
|
self.ws = CBPiWebSocket(self)
|
||||||
|
|
||||||
self.translation = TranslationController(self)
|
|
||||||
self.actor = ActorController(self)
|
self.actor = ActorController(self)
|
||||||
self.sensor = SensorController(self)
|
self.sensor = SensorController(self)
|
||||||
self.plugin = PluginController(self)
|
self.plugin = PluginController(self)
|
||||||
self.log = LogController(self)
|
self.log = LogController(self)
|
||||||
self.system = SystemController(self)
|
self.system = SystemController(self)
|
||||||
|
|
||||||
self.kettle = KettleController(self)
|
self.kettle = KettleController(self)
|
||||||
self.step = StepController(self)
|
self.step = StepController(self)
|
||||||
self.step2 = StepControllerNg(self)
|
|
||||||
self.dashboard = DashboardController(self)
|
self.dashboard = DashboardController(self)
|
||||||
|
|
||||||
|
|
||||||
self.http_step = StepHttpEndpoints(self)
|
self.http_step = StepHttpEndpoints(self)
|
||||||
self.http_step2 = StepHttpEndpoints2(self)
|
|
||||||
self.http_sensor = SensorHttpEndpoints(self)
|
self.http_sensor = SensorHttpEndpoints(self)
|
||||||
self.http_config = ConfigHttpEndpoints(self)
|
self.http_config = ConfigHttpEndpoints(self)
|
||||||
self.http_actor = ActorHttpEndpoints(self)
|
self.http_actor = ActorHttpEndpoints(self)
|
||||||
self.http_kettle = KettleHttpEndpoints(self)
|
self.http_kettle = KettleHttpEndpoints(self)
|
||||||
self.http_dashboard = DashBoardHttpEndpoints(self)
|
self.http_dashboard = DashBoardHttpEndpoints(self)
|
||||||
self.http_translation = TranslationHttpEndpoint(self)
|
|
||||||
self.http_plugin = PluginHttpEndpoints(self)
|
self.http_plugin = PluginHttpEndpoints(self)
|
||||||
self.http_system = SystemHttpEndpoints(self)
|
self.http_system = SystemHttpEndpoints(self)
|
||||||
self.notification = NotificationController(self)
|
self.notification = NotificationController(self)
|
||||||
|
@ -156,7 +155,7 @@ class CraftBeerPi():
|
||||||
http_method = method.__getattribute__("method")
|
http_method = method.__getattribute__("method")
|
||||||
path = method.__getattribute__("path")
|
path = method.__getattribute__("path")
|
||||||
class_name = method.__self__.__class__.__name__
|
class_name = method.__self__.__class__.__name__
|
||||||
logger.info("Register Endpoint : %s.%s %s %s%s " % (class_name, method.__name__, http_method, url_prefix, path))
|
logger.debug("Register Endpoint : %s.%s %s %s%s " % (class_name, method.__name__, http_method, url_prefix, path))
|
||||||
|
|
||||||
def add_post():
|
def add_post():
|
||||||
routes.append(web.post(method.__getattribute__("path"), method))
|
routes.append(web.post(method.__getattribute__("path"), method))
|
||||||
|
@ -178,7 +177,6 @@ class CraftBeerPi():
|
||||||
}
|
}
|
||||||
switcher[http_method]()
|
switcher[http_method]()
|
||||||
|
|
||||||
print("URL PREFIX", url_prefix)
|
|
||||||
if url_prefix != "/":
|
if url_prefix != "/":
|
||||||
logger.debug("URL Prefix: %s " % (url_prefix,))
|
logger.debug("URL Prefix: %s " % (url_prefix,))
|
||||||
sub = web.Application()
|
sub = web.Application()
|
||||||
|
@ -199,12 +197,10 @@ class CraftBeerPi():
|
||||||
long_description = """
|
long_description = """
|
||||||
This is the api for CraftBeerPi
|
This is the api for CraftBeerPi
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print("SWAGGER.......")
|
|
||||||
setup_swagger(self.app,
|
setup_swagger(self.app,
|
||||||
description=long_description,
|
description=long_description,
|
||||||
title=self.static_config.get("name", "CraftBeerPi 4.0"),
|
title="CraftBeerPi",
|
||||||
api_version=self.static_config.get("version", "4.0"),
|
api_version=self.version,
|
||||||
contact="info@craftbeerpi.com")
|
contact="info@craftbeerpi.com")
|
||||||
|
|
||||||
def notify(self, key: str, message: str, type: str = "info") -> None:
|
def notify(self, key: str, message: str, type: str = "info") -> None:
|
||||||
|
@ -227,13 +223,15 @@ class CraftBeerPi():
|
||||||
def _print_logo(self):
|
def _print_logo(self):
|
||||||
from pyfiglet import Figlet
|
from pyfiglet import Figlet
|
||||||
f = Figlet(font='big')
|
f = Figlet(font='big')
|
||||||
logger.info("\n%s" % f.renderText("%s %s" % (self.static_config.get("name"), self.static_config.get("version"))))
|
logger.info("\n%s" % f.renderText("CraftBeerPi %s " % self.version))
|
||||||
|
logger.info("www.CraftBeerPi.com")
|
||||||
|
logger.info("(c) 2021 Manuel Fritsch")
|
||||||
|
|
||||||
|
|
||||||
def _setup_http_index(self):
|
def _setup_http_index(self):
|
||||||
async def http_index(request):
|
async def http_index(request):
|
||||||
url = self.config.static.get("index_url")
|
url = self.config.static.get("index_url")
|
||||||
|
py
|
||||||
if url is not None:
|
if url is not None:
|
||||||
|
|
||||||
raise web.HTTPFound(url)
|
raise web.HTTPFound(url)
|
||||||
|
@ -250,12 +248,11 @@ class CraftBeerPi():
|
||||||
await self.job.init()
|
await self.job.init()
|
||||||
await DBModel.setup()
|
await DBModel.setup()
|
||||||
await self.config.init()
|
await self.config.init()
|
||||||
await self.translation.init()
|
|
||||||
self._setup_http_index()
|
self._setup_http_index()
|
||||||
self.plugin.load_plugins()
|
self.plugin.load_plugins()
|
||||||
self.plugin.load_plugins_from_evn()
|
self.plugin.load_plugins_from_evn()
|
||||||
await self.sensor.init()
|
await self.sensor.init()
|
||||||
await self.step2.init()
|
await self.step.init()
|
||||||
await self.actor.init()
|
await self.actor.init()
|
||||||
await self.kettle.init()
|
await self.kettle.init()
|
||||||
await self.call_initializer(self.app)
|
await self.call_initializer(self.app)
|
||||||
|
|
|
@ -19,25 +19,30 @@ except Exception:
|
||||||
patcher.start()
|
patcher.start()
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
class CustomActor(CBPiActor):
|
class CustomActor(CBPiActor2):
|
||||||
|
|
||||||
|
|
||||||
|
my_name = ""
|
||||||
|
|
||||||
# Custom property which can be configured by the user
|
# Custom property which can be configured by the user
|
||||||
@action("test", parameters={})
|
@action("test", parameters={})
|
||||||
def action1(self):
|
async def action1(self, **kwargs):
|
||||||
|
print("ACTION !", kwargs)
|
||||||
|
self.my_name = kwargs.get("name")
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
|
print("INIT")
|
||||||
|
|
||||||
self.state = False
|
self.state = False
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on(self, power=0):
|
async def on(self, power=0):
|
||||||
logger.info("ACTOR %s ON" % self.id)
|
logger.info("ACTOR 1111 %s ON" % self.id)
|
||||||
self.state = True
|
self.state = True
|
||||||
|
|
||||||
def off(self):
|
async def off(self):
|
||||||
logger.info("ACTOR %s OFF " % self.id)
|
logger.info("ACTOR %s OFF " % self.id)
|
||||||
self.state = False
|
self.state = False
|
||||||
|
|
||||||
|
@ -45,6 +50,9 @@ class CustomActor(CBPiActor):
|
||||||
|
|
||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GPIOActor(CBPiActor):
|
class GPIOActor(CBPiActor):
|
||||||
|
|
||||||
|
|
|
@ -2,69 +2,14 @@ import asyncio
|
||||||
|
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
class CustomLogic(CBPiKettleLogic):
|
class CustomLogic(CBPiKettleLogic2):
|
||||||
|
|
||||||
test = Property.Number(label="Test")
|
|
||||||
|
|
||||||
running = True
|
|
||||||
|
|
||||||
|
|
||||||
async def wait_for_event(self, topic, callback=None, timeout=None):
|
|
||||||
|
|
||||||
|
|
||||||
future_obj = self.cbpi.app.loop.create_future()
|
|
||||||
|
|
||||||
async def default_callback(id, **kwargs):
|
|
||||||
future_obj.set_result("HELLO")
|
|
||||||
|
|
||||||
|
|
||||||
if callback is None:
|
|
||||||
self.cbpi.bus.register(topic=topic, method=default_callback)
|
|
||||||
else:
|
|
||||||
callback.future = future_obj
|
|
||||||
self.cbpi.bus.register(topic=topic, method=callback)
|
|
||||||
|
|
||||||
if timeout is not None:
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
await asyncio.wait_for(future_obj, timeout=timeout)
|
|
||||||
|
|
||||||
return future_obj.result()
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
|
|
||||||
await future_obj
|
|
||||||
return future_obj.result()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def run(self):
|
|
||||||
|
|
||||||
'''
|
|
||||||
async def my_callback(value, **kwargs):
|
|
||||||
|
|
||||||
if value == 5:
|
|
||||||
self.cbpi.bus.unregister(my_callback)
|
|
||||||
kwargs["future"].set_result("AMAZING")
|
|
||||||
else:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
result = await self.wait_for_event("sensor/1/data", callback=my_callback)
|
@action(key="test", parameters=[])
|
||||||
'''
|
async def action1(self, **kwargs):
|
||||||
|
print("ACTION")
|
||||||
|
|
||||||
value = 0
|
|
||||||
|
|
||||||
|
|
||||||
while self.running:
|
|
||||||
|
|
||||||
value = value + 1
|
|
||||||
print(value)
|
|
||||||
if value >= 10:
|
|
||||||
|
|
||||||
break
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
import re
|
|
||||||
import random
|
|
||||||
class CustomSensor(CBPiSensor):
|
class CustomSensor(CBPiSensor):
|
||||||
|
|
||||||
# Custom Properties which will can be configured by the user
|
# Custom Properties which will can be configured by the user
|
||||||
|
@ -48,6 +50,34 @@ class CustomSensor(CBPiSensor):
|
||||||
self.log_data(self.value)
|
self.log_data(self.value)
|
||||||
await cbpi.bus.fire("sensor/%s/data" % self.id, value=self.value)
|
await cbpi.bus.fire("sensor/%s/data" % self.id, value=self.value)
|
||||||
|
|
||||||
|
@parameters([Property.Number(label="Param1", configurable=True),
|
||||||
|
Property.Text(label="Param2", configurable=True, default_value="HALLO"),
|
||||||
|
Property.Select(label="Param3", options=[1,2,4]),
|
||||||
|
Property.Sensor(label="Param4"),
|
||||||
|
Property.Actor(label="Param5")])
|
||||||
|
class CustomSensor2(CBPiSensor2):
|
||||||
|
|
||||||
|
@action(key="Test", parameters=[])
|
||||||
|
async def action1(self, **kwargs):
|
||||||
|
print("ACTION!", kwargs)
|
||||||
|
|
||||||
|
@action(key="Test1", parameters=[])
|
||||||
|
async def action2(self, **kwargs):
|
||||||
|
print("ACTION!", kwargs)
|
||||||
|
|
||||||
|
@action(key="Test2", parameters=[])
|
||||||
|
async def action3(self, **kwargs):
|
||||||
|
|
||||||
|
print("ACTION!", kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
|
||||||
|
while self.running is True:
|
||||||
|
print("HALLO")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
|
|
||||||
|
@ -58,5 +88,5 @@ def setup(cbpi):
|
||||||
:param cbpi: the cbpi core
|
:param cbpi: the cbpi core
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
cbpi.plugin.register("CustomSensor2", CustomSensor2)
|
||||||
cbpi.plugin.register("CustomSensor", CustomSensor)
|
#cbpi.plugin.register("CustomSensor", CustomSensor)
|
||||||
|
|
|
@ -4,59 +4,33 @@ import time
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class CustomStepCBPi(CBPiSimpleStep):
|
@parameters([Property.Number(label="Param1", configurable=True),
|
||||||
|
Property.Text(label="Param2", configurable=True, default_value="HALLO"),
|
||||||
name1 = Property.Number(label="Test", configurable=True)
|
Property.Select(label="Param3", options=[1,2,4]),
|
||||||
timer_end = Property.Number(label="Test", default_value=None)
|
Property.Sensor(label="Param4"),
|
||||||
temp = Property.Number(label="Temperature", default_value=50, configurable=True)
|
Property.Actor(label="Param5")])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
@action(key="name", parameters=None)
|
|
||||||
def test(self, **kwargs):
|
|
||||||
self.name="WOOHOO"
|
|
||||||
|
|
||||||
def get_status(self):
|
|
||||||
return "Status: %s Temp" % self.temp
|
|
||||||
|
|
||||||
async def run_cycle(self):
|
|
||||||
|
|
||||||
self.next()
|
|
||||||
|
|
||||||
'''
|
|
||||||
print("RUN", self.name1, self.managed_fields, self.timer_end)
|
|
||||||
self.i = self.i + 1
|
|
||||||
|
|
||||||
if self.timer_end is None:
|
|
||||||
self.timer_end = time.time() + 10
|
|
||||||
|
|
||||||
if self.i == 10:
|
|
||||||
self.next()
|
|
||||||
'''
|
|
||||||
|
|
||||||
#self.cbpi.notify(key="step", message="HELLO FROM STEP")
|
|
||||||
|
|
||||||
@parameters([Property.Number(label="Test", configurable=True), Property.Text(label="Test", configurable=True, default_value="HALLO")])
|
|
||||||
class Step2(CBPiStep):
|
class Step2(CBPiStep):
|
||||||
|
|
||||||
i = 0
|
@action(key="name2", parameters=[])
|
||||||
|
async def action2(self, **kwargs):
|
||||||
|
print("CALL ACTION")
|
||||||
|
|
||||||
@action(key="name", parameters=[Property.Number(label="Test", configurable=True)])
|
@action(key="name", parameters=[Property.Number(label="Test", configurable=True)])
|
||||||
async def action(self, **kwargs):
|
async def action(self, **kwargs):
|
||||||
print("HALLO")
|
print("CALL ACTION")
|
||||||
|
|
||||||
async def execute(self):
|
async def execute(self):
|
||||||
|
count = self.props.get("count", 0)
|
||||||
|
self.state_msg = "COUNT %s" % count
|
||||||
|
|
||||||
print(self.props)
|
self.props["count"] += 1
|
||||||
self.i += 1
|
|
||||||
print(self.i)
|
|
||||||
self.state_msg = "COUNT %s" % self.i
|
|
||||||
await self.update(self.props)
|
await self.update(self.props)
|
||||||
print("JETZT GEHTS LO")
|
|
||||||
#raise Exception("RROR")
|
|
||||||
|
|
||||||
|
if count >= 5:
|
||||||
|
self.next()
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
self.props["count"] = 0
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
'''
|
'''
|
||||||
|
@ -67,4 +41,4 @@ def setup(cbpi):
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
cbpi.plugin.register("CustomStep2", Step2)
|
cbpi.plugin.register("CustomStep2", Step2)
|
||||||
cbpi.plugin.register("CustomStepCBPi", CustomStepCBPi)
|
|
||||||
|
|
|
@ -31,5 +31,10 @@ def setup(cbpi):
|
||||||
:param cbpi: the cbpi core
|
:param cbpi: the cbpi core
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
print("MQTT")
|
||||||
|
print("###################")
|
||||||
|
print("###################")
|
||||||
|
print("###################")
|
||||||
|
print("###################")
|
||||||
client = CBPiMqttClient(cbpi)
|
client = CBPiMqttClient(cbpi)
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,14 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
|
|
||||||
auth = False
|
auth = False
|
||||||
|
|
||||||
class ActorHttpEndpoints(HttpCrudEndpoints):
|
class ActorHttpEndpoints():
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super().__init__(cbpi)
|
self.cbpi = cbpi
|
||||||
self.controller = cbpi.actor
|
self.controller = cbpi.actor
|
||||||
self.cbpi.register(self, "/actor")
|
self.cbpi.register(self, "/actor")
|
||||||
|
|
||||||
@request_mapping(path="/types", auth_required=False)
|
|
||||||
async def get_types(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get all actor types
|
|
||||||
tags:
|
|
||||||
- Actor
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().get_types(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
@request_mapping(path="/", auth_required=False)
|
||||||
async def http_get_all(self, request):
|
async def http_get_all(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -37,29 +21,8 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_get_all(request)
|
return web.json_response(data=self.controller.get_state())
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", auth_required=False)
|
|
||||||
async def http_get_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get one Actor
|
|
||||||
tags:
|
|
||||||
- Actor
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Actor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"405":
|
|
||||||
description: invalid HTTP Met
|
|
||||||
"""
|
|
||||||
return await super().http_get_one(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
@request_mapping(path="/", method="POST", auth_required=False)
|
||||||
async def http_add(self, request):
|
async def http_add(self, request):
|
||||||
|
@ -73,21 +36,30 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
name: body
|
name: body
|
||||||
description: Created an actor
|
description: Created an actor
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
config:
|
props:
|
||||||
type: object
|
type: object
|
||||||
|
example:
|
||||||
|
name: "Actor 1"
|
||||||
|
type: "CustomActor"
|
||||||
|
props: {}
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
|
data = await request.json()
|
||||||
|
response_data = await self.controller.add(data)
|
||||||
|
|
||||||
return await super().http_add(request)
|
return web.json_response(data=self.controller.create_dict(response_data))
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
||||||
|
@ -116,14 +88,14 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
config:
|
config:
|
||||||
type: object
|
props: object
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
print(".........")
|
id = request.match_info['id']
|
||||||
print(request)
|
data = await request.json()
|
||||||
return await super().http_update(request)
|
return web.json_response(data=self.controller.create_dict(await self.controller.update(id, data)))
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
||||||
async def http_delete_one(self, request):
|
async def http_delete_one(self, request):
|
||||||
|
@ -137,15 +109,16 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
in: "path"
|
in: "path"
|
||||||
description: "Actor ID"
|
description: "Actor ID"
|
||||||
required: true
|
required: true
|
||||||
type: "integer"
|
type: "string"
|
||||||
format: "int64"
|
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_delete_one(request)
|
id = request.match_info['id']
|
||||||
|
await self.controller.delete(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/on", method="POST", auth_required=auth)
|
@request_mapping(path="/{id}/on", method="POST", auth_required=False)
|
||||||
async def http_on(self, request) -> web.Response:
|
async def http_on(self, request) -> web.Response:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -159,27 +132,24 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
in: "path"
|
in: "path"
|
||||||
description: "Actor ID"
|
description: "Actor ID"
|
||||||
required: true
|
required: true
|
||||||
type: "integer"
|
type: "string"
|
||||||
format: "int64"
|
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"405":
|
"405":
|
||||||
description: invalid HTTP Met
|
description: invalid HTTP Met
|
||||||
"""
|
"""
|
||||||
actor_id = int(request.match_info['id'])
|
id = request.match_info['id']
|
||||||
result = await self.cbpi.bus.fire(topic="actor/%s/switch/on" % actor_id, actor_id=actor_id, power=99)
|
await self.controller.on(id)
|
||||||
for key, value in result.results.items():
|
|
||||||
pass
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/off", method="POST", auth_required=False)
|
||||||
@request_mapping(path="/{id:\d+}/off", method="POST", auth_required=auth)
|
|
||||||
async def http_off(self, request) -> web.Response:
|
async def http_off(self, request) -> web.Response:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
---
|
---
|
||||||
description: Switch actor off
|
description: Switch actor on
|
||||||
tags:
|
tags:
|
||||||
- Actor
|
- Actor
|
||||||
|
|
||||||
|
@ -188,48 +158,20 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
in: "path"
|
in: "path"
|
||||||
description: "Actor ID"
|
description: "Actor ID"
|
||||||
required: true
|
required: true
|
||||||
type: "integer"
|
type: "string"
|
||||||
format: "int64"
|
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"405":
|
"405":
|
||||||
description: invalid HTTP Met
|
description: invalid HTTP Met
|
||||||
"""
|
"""
|
||||||
actor_id = int(request.match_info['id'])
|
id = request.match_info['id']
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/off" % actor_id, actor_id=actor_id)
|
await self.controller.off(id)
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/toggle", method="POST", auth_required=auth)
|
|
||||||
async def http_toggle(self, request) -> web.Response:
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
@request_mapping(path="/{id}/action", method="POST", auth_required=auth)
|
||||||
description: Toogle an actor on or off
|
|
||||||
tags:
|
|
||||||
- Actor
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Actor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"405":
|
|
||||||
description: invalid HTTP Met
|
|
||||||
"""
|
|
||||||
actor_id = int(request.match_info['id'])
|
|
||||||
if await request.text():
|
|
||||||
data = await request.json()
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % actor_id, time=data.get("time"), actor_id=actor_id)
|
|
||||||
else:
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % actor_id, actor_id=actor_id)
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/action", method="POST", auth_required=auth)
|
|
||||||
async def http_action(self, request) -> web.Response:
|
async def http_action(self, request) -> web.Response:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -253,13 +195,14 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
config:
|
parameter:
|
||||||
type: object
|
type: object
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
actor_id = int(request.match_info['id'])
|
actor_id = request.match_info['id']
|
||||||
|
data = await request.json()
|
||||||
|
await self.controller.call_action(actor_id, data.get("name"), data.get("parameter"))
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/action" % actor_id, actor_id=actor_id, data=await request.json())
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
|
@ -13,114 +13,8 @@ class DashBoardHttpEndpoints(HttpCrudEndpoints):
|
||||||
self.controller = cbpi.dashboard
|
self.controller = cbpi.dashboard
|
||||||
self.cbpi.register(self, "/dashboard")
|
self.cbpi.register(self, "/dashboard")
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
|
||||||
async def http_get_all(self, request):
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Get all dashboards
|
|
||||||
tags:
|
|
||||||
- Dashboard
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_get_all(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", auth_required=False)
|
|
||||||
async def http_get_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get one Dashboard by id
|
|
||||||
tags:
|
|
||||||
- Dashboard
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Actor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_get_one(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
|
||||||
async def http_add(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Create a new Dashboard
|
|
||||||
tags:
|
|
||||||
- Dashboard
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Create a new Dashboard
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
return await super().http_add(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", method="PUT", auth_required=False)
|
|
||||||
async def http_update(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Update a Dashboard
|
|
||||||
tags:
|
|
||||||
- Dashboard
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Dashboard ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Update a dashboard
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_update(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", method="DELETE", auth_required=False)
|
|
||||||
async def http_delete_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Delete a Dashboard
|
|
||||||
tags:
|
|
||||||
- Dashboard
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Dashboard ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
id = request.match_info['id']
|
|
||||||
await self.cbpi.dashboard.delete_dashboard(id)
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/content", auth_required=False)
|
@request_mapping(path="/{id:\d+}/content", auth_required=False)
|
||||||
async def get_content(self, request):
|
async def get_content(self, request):
|
||||||
|
@ -141,8 +35,6 @@ class DashBoardHttpEndpoints(HttpCrudEndpoints):
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
dashboard_id = int(request.match_info['id'])
|
dashboard_id = int(request.match_info['id'])
|
||||||
|
|
||||||
|
|
||||||
return web.json_response(await self.cbpi.dashboard.get_content(dashboard_id), dumps=json_dumps)
|
return web.json_response(await self.cbpi.dashboard.get_content(dashboard_id), dumps=json_dumps)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,229 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
auth = False
|
auth = False
|
||||||
|
|
||||||
|
class KettleHttpEndpoints():
|
||||||
|
|
||||||
class KettleHttpEndpoints(HttpCrudEndpoints):
|
def __init__(self, cbpi):
|
||||||
|
self.cbpi = cbpi
|
||||||
@request_mapping(path="/types", auth_required=False)
|
self.controller = cbpi.kettle
|
||||||
async def get_types(self, request):
|
self.cbpi.register(self, "/kettle")
|
||||||
return await super().get_types(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
@request_mapping(path="/", auth_required=False)
|
||||||
async def http_get_all(self, request):
|
async def http_get_all(self, request):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
---
|
---
|
||||||
description: Get all kettles
|
description: Switch actor on
|
||||||
tags:
|
tags:
|
||||||
- Kettle
|
- Kettle
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_get_all(request)
|
return web.json_response(data=self.controller.get_state())
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", auth_required=False)
|
|
||||||
async def http_get_one(self, request):
|
@request_mapping(path="/", method="POST", auth_required=False)
|
||||||
|
async def http_add(self, request):
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Get Kettle by Id
|
description: add one Actor
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: Created an actor
|
||||||
|
required: true
|
||||||
|
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
sensor:
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
heater:
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
agitator:
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
target_temp:
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
props:
|
||||||
|
type: object
|
||||||
|
example:
|
||||||
|
name: "Kettle 1"
|
||||||
|
type: "CustomKettleLogic"
|
||||||
|
props: {}
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
data = await request.json()
|
||||||
|
response_data = await self.controller.add(data)
|
||||||
|
|
||||||
|
return web.json_response(data=self.controller.create_dict(response_data))
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
||||||
|
async def http_update(self, request):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
description: Update an actor
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: Update an actor
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
config:
|
||||||
|
props: object
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
data = await request.json()
|
||||||
|
return web.json_response(data=self.controller.create_dict(await self.controller.update(id, data)))
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
||||||
|
async def http_delete_one(self, request):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
description: Delete an actor
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.delete(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/on", method="POST", auth_required=False)
|
||||||
|
async def http_on(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Switch actor on
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"405":
|
||||||
|
description: invalid HTTP Met
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.start(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/off", method="POST", auth_required=False)
|
||||||
|
async def http_off(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Switch actor on
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"405":
|
||||||
|
description: invalid HTTP Met
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.off(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/action", method="POST", auth_required=auth)
|
||||||
|
async def http_action(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Toogle an actor on or off
|
||||||
|
tags:
|
||||||
|
- Kettle
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: Update an actor
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
parameter:
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
actor_id = request.match_info['id']
|
||||||
|
data = await request.json()
|
||||||
|
await self.controller.call_action(actor_id, data.get("name"), data.get("parameter"))
|
||||||
|
|
||||||
|
return web.Response(status=204)
|
||||||
|
@request_mapping(path="/{id}/target_temp", method="POST", auth_required=auth)
|
||||||
|
async def http_target(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Toogle an actor on or off
|
||||||
tags:
|
tags:
|
||||||
- Kettle
|
- Kettle
|
||||||
parameters:
|
parameters:
|
||||||
|
@ -42,287 +237,7 @@ class KettleHttpEndpoints(HttpCrudEndpoints):
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_get_one(request)
|
id = request.match_info['id']
|
||||||
|
#data = await request.json()
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
await self.controller.set_target_temp(id,999)
|
||||||
async def http_add(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: add a kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Created an kettle
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
sensor:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
heater:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
agitator:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
target_temp:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
logic:
|
|
||||||
type: string
|
|
||||||
config:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_add(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
|
||||||
async def http_update(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Update a kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Created an kettle
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
sensor:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
heater:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
agitator:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
target_temp:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
logic:
|
|
||||||
type: string
|
|
||||||
config:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_update(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
|
||||||
async def http_delete_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Delete a kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_delete_one(request)
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
super().__init__(cbpi)
|
|
||||||
self.controller = cbpi.kettle
|
|
||||||
self.cbpi.register(self, "/kettle")
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/automatic", method="POST", auth_required=False)
|
|
||||||
async def http_automatic(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Toggle Automatic
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.controller.toggle_automtic(int(request.match_info['id']))
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/heater/on", auth_required=False)
|
|
||||||
async def http_heater_on(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Kettle Heater on
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.controller.heater_on(int(request.match_info['id']))
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/heater/off", auth_required=False)
|
|
||||||
async def http_heater_off(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Kettle Heater off
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.controller.heater_off(int(request.match_info['id']))
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/agitator/on", auth_required=False)
|
|
||||||
async def http_agitator_on(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Kettle Agitator on
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.controller.agitator_on(int(request.match_info['id']))
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/agitator/off", auth_required=False)
|
|
||||||
async def http_agitator_off(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Kettle Agitator off
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.controller.agitator_off(int(request.match_info['id']))
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/targettemp", auth_required=False)
|
|
||||||
async def http_taget_temp(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get Target Temp of kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
kettle_id = int(request.match_info['id'])
|
|
||||||
temp = await self.controller.get_traget_temp(kettle_id)
|
|
||||||
return web.json_response(data=dict(target_temp=temp, kettle_id=kettle_id))
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/temp/{temp:\d+}", method="PUT", auth_required=False)
|
|
||||||
async def http_set_taget_temp(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get Target Temp of kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
kettle_id = int(request.match_info['id'])
|
|
||||||
target_temp = int(request.match_info['temp'])
|
|
||||||
await self.cbpi.bus.fire(topic="kettle/%s/targettemp" % kettle_id, kettle_id=kettle_id, target_temp=target_temp)
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/temp", auth_required=False)
|
|
||||||
async def http_temp(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get Temp of kettle
|
|
||||||
tags:
|
|
||||||
- Kettle
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Kettle ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
kettle_id = int(request.match_info['id'])
|
|
||||||
temp = await self.controller.get_temp(kettle_id)
|
|
||||||
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
|
@ -1,186 +1,72 @@
|
||||||
import asyncio
|
|
||||||
import os
|
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
from cbpi.api import *
|
||||||
|
auth = False
|
||||||
|
|
||||||
from cbpi.api import request_mapping
|
class SensorHttpEndpoints():
|
||||||
|
|
||||||
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
|
|
||||||
|
|
||||||
class SensorHttpEndpoints(HttpCrudEndpoints):
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super().__init__(cbpi)
|
self.cbpi = cbpi
|
||||||
self.controller = cbpi.sensor
|
self.controller = cbpi.sensor
|
||||||
self.cbpi.register(self, "/sensor")
|
self.cbpi.register(self, "/sensor")
|
||||||
|
|
||||||
@request_mapping(path="/types", auth_required=False)
|
|
||||||
async def get_types(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get all sensor types
|
|
||||||
tags:
|
|
||||||
- Sensor
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().get_types(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
@request_mapping(path="/", auth_required=False)
|
||||||
async def http_get_all(self, request):
|
async def http_get_all(self, request):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
---
|
---
|
||||||
description: Get all sensor
|
description: Switch actor on
|
||||||
tags:
|
tags:
|
||||||
- Sensor
|
- Sensor
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_get_all(request)
|
return web.json_response(data=self.controller.get_state())
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", auth_required=False)
|
|
||||||
async def http_get_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get an sensor
|
|
||||||
tags:
|
|
||||||
- Sensor
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Sensor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"405":
|
|
||||||
description: invalid HTTP Met
|
|
||||||
"""
|
|
||||||
return await super().http_get_one(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
@request_mapping(path="/", method="POST", auth_required=False)
|
||||||
async def http_add(self, request):
|
async def http_add(self, request):
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Get one sensor
|
description: add one Actor
|
||||||
tags:
|
tags:
|
||||||
- Sensor
|
- Sensor
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: body
|
name: body
|
||||||
description: Created an sensor
|
description: Created an actor
|
||||||
required: false
|
required: true
|
||||||
|
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
config:
|
props:
|
||||||
type: object
|
type: object
|
||||||
|
example:
|
||||||
|
name: "Actor 1"
|
||||||
|
type: "CustomActor"
|
||||||
|
props: {}
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_add(request)
|
data = await request.json()
|
||||||
|
response_data = await self.controller.add(data)
|
||||||
|
|
||||||
|
return web.json_response(data=self.controller.create_dict(response_data))
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
||||||
async def http_update(self, request):
|
async def http_update(self, request):
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Update an sensor
|
description: Update an actor
|
||||||
tags:
|
|
||||||
- Sensor
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Sensor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Update an sensor
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
config:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_update(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
|
||||||
async def http_delete_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Delete an sensor
|
|
||||||
tags:
|
|
||||||
- Sensor
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "Sensor ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_delete_one(request)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/log", auth_required=False)
|
|
||||||
async def http_get_log(self, request):
|
|
||||||
sensor_id = request.match_info['id']
|
|
||||||
resp = web.StreamResponse(status=200, reason='OK', headers={'Content-Type': 'text/html'})
|
|
||||||
|
|
||||||
await resp.prepare(request)
|
|
||||||
for filename in sorted(os.listdir("./logs/sensors"), reverse=True):
|
|
||||||
if filename.startswith("sensor_%s" % sensor_id):
|
|
||||||
|
|
||||||
with open(os.path.join("./logs/sensors/%s" % filename), 'r') as myfile:
|
|
||||||
await resp.write(str.encode(myfile.read()))
|
|
||||||
return resp
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/log", method="DELETE", auth_required=False)
|
|
||||||
async def http_clear_log(self, request):
|
|
||||||
sensor_id = request.match_info['id']
|
|
||||||
|
|
||||||
for filename in sorted(os.listdir("./logs/sensors"), reverse=True):
|
|
||||||
|
|
||||||
if filename == "sensor_%s.log" % sensor_id:
|
|
||||||
with open(os.path.join("./logs/sensors/%s" % filename), 'w'):
|
|
||||||
pass
|
|
||||||
continue
|
|
||||||
if filename.startswith("sensor_%s" % sensor_id):
|
|
||||||
os.remove(os.path.join("./logs/sensors/%s" % filename))
|
|
||||||
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}/action", method="POST", auth_required=False)
|
|
||||||
async def http_action(self, request) -> web.Response:
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Execute action on sensor
|
|
||||||
tags:
|
tags:
|
||||||
- Sensor
|
- Sensor
|
||||||
parameters:
|
parameters:
|
||||||
|
@ -199,13 +85,122 @@ class SensorHttpEndpoints(HttpCrudEndpoints):
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
config:
|
config:
|
||||||
|
props: object
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
data = await request.json()
|
||||||
|
return web.json_response(data=self.controller.create_dict(await self.controller.update(id, data)))
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
||||||
|
async def http_delete_one(self, request):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
description: Delete an actor
|
||||||
|
tags:
|
||||||
|
- Sensor
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.delete(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/on", method="POST", auth_required=False)
|
||||||
|
async def http_on(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Switch actor on
|
||||||
|
tags:
|
||||||
|
- Sensor
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"405":
|
||||||
|
description: invalid HTTP Met
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.on(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/off", method="POST", auth_required=False)
|
||||||
|
async def http_off(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Switch actor on
|
||||||
|
tags:
|
||||||
|
- Sensor
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "string"
|
||||||
|
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"405":
|
||||||
|
description: invalid HTTP Met
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.off(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}/action", method="POST", auth_required=auth)
|
||||||
|
async def http_action(self, request) -> web.Response:
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Toogle an actor on or off
|
||||||
|
tags:
|
||||||
|
- Sensor
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Actor ID"
|
||||||
|
required: true
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: Update an actor
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
parameter:
|
||||||
type: object
|
type: object
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
sensor_id = int(request.match_info['id'])
|
actor_id = request.match_info['id']
|
||||||
|
data = await request.json()
|
||||||
|
await self.controller.call_action(actor_id, data.get("name"), data.get("parameter"))
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="sensor/%s/action" % sensor_id, sensor_id=sensor_id, data=await request.json())
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
|
@ -1,257 +1,211 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi.api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
|
class StepHttpEndpoints():
|
||||||
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
|
|
||||||
|
|
||||||
class StepHttpEndpoints(HttpCrudEndpoints):
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super().__init__(cbpi)
|
self.cbpi = cbpi
|
||||||
self.controller = cbpi.step
|
self.controller = cbpi.step
|
||||||
self.cbpi.register(self, "/step")
|
self.cbpi.register(self, "/step2")
|
||||||
|
|
||||||
|
def create_dict(self, data):
|
||||||
|
return dict(name=data["name"], id=data["id"], type=data.get("type"), status=data["status"],props=data["props"], state_text=data["instance"].get_state())
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/types", auth_required=False)
|
@request_mapping(path="/", auth_required=False)
|
||||||
async def get_types(self, request):
|
async def http_get_all(self, request):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Get all step types
|
description: Get all steps
|
||||||
tags:
|
tags:
|
||||||
- Step
|
- Step
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().get_types(request)
|
return web.json_response(data=self.controller.get_state())
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
|
||||||
async def http_get_all(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Get all steps
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_get_all(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id:\d+}", auth_required=False)
|
|
||||||
async def http_get_one(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get one step
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "step ID"
|
|
||||||
required: true
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"405":
|
|
||||||
description: invalid HTTP Met
|
|
||||||
"""
|
|
||||||
return await super().http_get_one(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
@request_mapping(path="/", method="POST", auth_required=False)
|
||||||
async def http_add(self, request):
|
async def http_add(self, request):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
---
|
---
|
||||||
description: Get one step
|
description: Add
|
||||||
tags:
|
tags:
|
||||||
- Step
|
- Step
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: body
|
name: body
|
||||||
description: Created an step
|
description: Created an step
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
config:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return await super().http_add(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
|
||||||
async def http_update(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Update an step
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
parameters:
|
|
||||||
- name: "id"
|
|
||||||
in: "path"
|
|
||||||
description: "step ID"
|
|
||||||
required: true
|
required: true
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Update an step
|
|
||||||
required: false
|
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
config:
|
|
||||||
type: object
|
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_update(request)
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
data = await request.json()
|
||||||
async def http_delete_one(self, request):
|
result = await self.controller.add(data)
|
||||||
|
return web.json_response(self.create_dict(result))
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
||||||
|
async def http_update(self, request):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Delete a step
|
description: Update
|
||||||
tags:
|
tags:
|
||||||
- Step
|
- Step
|
||||||
parameters:
|
parameters:
|
||||||
- name: "id"
|
- in: body
|
||||||
in: "path"
|
name: body
|
||||||
description: "Step ID"
|
description: Created an kettle
|
||||||
required: true
|
required: false
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = await request.json()
|
||||||
|
id = request.match_info['id']
|
||||||
|
result = await self.controller.update(id, data)
|
||||||
|
print("RESULT", result)
|
||||||
|
return web.json_response(self.create_dict(result))
|
||||||
|
|
||||||
|
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
||||||
|
async def http_delete(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Delete
|
||||||
|
tags:
|
||||||
|
- Step
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
id = request.match_info['id']
|
||||||
|
await self.controller.delete(id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/next", method="POST", auth_required=False)
|
||||||
|
async def http_next(self, request):
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Next
|
||||||
|
tags:
|
||||||
|
- Step
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self.controller.next()
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
|
@request_mapping(path="/move", method="PUT", auth_required=False)
|
||||||
|
async def http_move(self, request):
|
||||||
|
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
description: Move
|
||||||
|
tags:
|
||||||
|
- Step
|
||||||
|
parameters:
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: Created an kettle
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
direction:
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
return await super().http_delete_one(request)
|
data = await request.json()
|
||||||
|
await self.controller.move(data["id"], data["direction"])
|
||||||
@request_mapping(path="/", method="DELETE", auth_required=False)
|
|
||||||
async def http_delete_all(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Delete all step
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire("step/clear")
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/start", method="POST", auth_required=False)
|
||||||
@request_mapping(path="/action", method="POST", auth_required=False, json_schema={"action": str, "parameter": dict})
|
|
||||||
async def http_action(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Call Step Action
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Step Action
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
action:
|
|
||||||
type: string
|
|
||||||
parameter:
|
|
||||||
type: object
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"405":
|
|
||||||
description: invalid HTTP Method
|
|
||||||
"""
|
|
||||||
data = await request.json()
|
|
||||||
await self.cbpi.bus.fire("step/action", name=data["action"], parameter=data["parameter"])
|
|
||||||
return web.Response(text="OK")
|
|
||||||
|
|
||||||
@request_mapping(path="/start", auth_required=False)
|
|
||||||
async def http_start(self, request):
|
async def http_start(self, request):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
description: Start Brewing Process
|
description: Move
|
||||||
tags:
|
tags:
|
||||||
- Step
|
- Step
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
if self.controller.is_running():
|
|
||||||
raise CBPiException("Brewing Process Already Running")
|
await self.controller.start()
|
||||||
print("FIRE START FROM HTTP")
|
|
||||||
await self.cbpi.bus.fire("step/start")
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/stop", method="POST", auth_required=False)
|
||||||
@request_mapping(path="/reset", auth_required=False)
|
|
||||||
async def http_reset(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Reset Brewing Process
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.cbpi.bus.fire("step/reset")
|
|
||||||
return web.Response(text="OK")
|
|
||||||
|
|
||||||
@request_mapping(path="/next", auth_required=False)
|
|
||||||
async def http_next(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Start next step
|
|
||||||
tags:
|
|
||||||
- Step
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
await self.cbpi.bus.fire("step/next")
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/stop", auth_required=False)
|
|
||||||
async def http_stop(self, request):
|
async def http_stop(self, request):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
---
|
---
|
||||||
description: Stop next step
|
description: Stop Step
|
||||||
tags:
|
tags:
|
||||||
- Step
|
- Step
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
"""
|
"""
|
||||||
await self.cbpi.bus.fire("step/stop")
|
|
||||||
|
await self.controller.stop()
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
@request_mapping(path="/sort", method="POST", auth_required=False)
|
|
||||||
async def http_sort(self, request):
|
@request_mapping(path="/reset", method="POST", auth_required=False)
|
||||||
data = await request.json()
|
async def http_reset(self, request):
|
||||||
await self.cbpi.bus.fire("step/sort", data=data)
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Move
|
||||||
|
tags:
|
||||||
|
- Step
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self.controller.reset_all()
|
||||||
|
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/basic", method="PUT", auth_required=False)
|
||||||
|
async def http_save_basic(self, request):
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
---
|
||||||
|
description: Move
|
||||||
|
tags:
|
||||||
|
- Step
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
data = await request.json()
|
||||||
|
await self.controller.save_basic(data)
|
||||||
|
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
|
@ -1,200 +0,0 @@
|
||||||
from aiohttp import web
|
|
||||||
from cbpi.api import *
|
|
||||||
|
|
||||||
|
|
||||||
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
|
|
||||||
|
|
||||||
class StepHttpEndpoints2():
|
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.controller = cbpi.step2
|
|
||||||
self.cbpi.register(self, "/step2")
|
|
||||||
|
|
||||||
def create_dict(self, data):
|
|
||||||
return dict(name=data["name"], id=data["id"], type=data.get("type"), status=data["status"],props=data["props"], state_text=data["instance"].get_state())
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
|
||||||
async def http_get_all(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get all steps
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
return web.json_response(data=self.controller.get_state())
|
|
||||||
|
|
||||||
@request_mapping(path="/", method="POST", auth_required=False)
|
|
||||||
async def http_add(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Add
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Created an step
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = await request.json()
|
|
||||||
result = await self.controller.add(data)
|
|
||||||
print("RESULT", result)
|
|
||||||
return web.json_response(self.create_dict(result))
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="PUT", auth_required=False)
|
|
||||||
async def http_update(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Update
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Created an kettle
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = await request.json()
|
|
||||||
id = request.match_info['id']
|
|
||||||
result = await self.controller.update(id, data)
|
|
||||||
print("RESULT", result)
|
|
||||||
return web.json_response(self.create_dict(result))
|
|
||||||
|
|
||||||
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
|
|
||||||
async def http_delete(self, request):
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Delete
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
id = request.match_info['id']
|
|
||||||
await self.controller.delete(id)
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/next", method="POST", auth_required=False)
|
|
||||||
async def http_next(self, request):
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Next
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
await self.controller.next()
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/move", method="PUT", auth_required=False)
|
|
||||||
async def http_move(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Move
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: Created an kettle
|
|
||||||
required: false
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
direction:
|
|
||||||
type: "integer"
|
|
||||||
format: "int64"
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
data = await request.json()
|
|
||||||
print("MOVE", data)
|
|
||||||
await self.controller.move(data["id"], data["direction"])
|
|
||||||
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/start", method="POST", auth_required=False)
|
|
||||||
async def http_start(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Move
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
await self.controller.start()
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/stop", method="POST", auth_required=False)
|
|
||||||
async def http_stop(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Stop Step
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
await self.controller.stop()
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/reset", method="POST", auth_required=False)
|
|
||||||
async def http_reset(self, request):
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
---
|
|
||||||
description: Move
|
|
||||||
tags:
|
|
||||||
- Step2
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
print("RESE HTTP")
|
|
||||||
await self.controller.reset_all()
|
|
||||||
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
|
@ -26,9 +26,7 @@ class SystemHttpEndpoints:
|
||||||
actor=self.cbpi.actor.get_state(),
|
actor=self.cbpi.actor.get_state(),
|
||||||
sensor=self.cbpi.sensor.get_state(),
|
sensor=self.cbpi.sensor.get_state(),
|
||||||
kettle=self.cbpi.kettle.get_state(),
|
kettle=self.cbpi.kettle.get_state(),
|
||||||
step=self.cbpi.step2.get_state(),
|
step=self.cbpi.step.get_state(),
|
||||||
dashboard=self.cbpi.dashboard.get_state(),
|
|
||||||
translations=self.cbpi.translation.get_all(),
|
|
||||||
config=self.cbpi.config.get_state())
|
config=self.cbpi.config.get_state())
|
||||||
, dumps=json_dumps)
|
, dumps=json_dumps)
|
||||||
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
from aiohttp import web
|
|
||||||
from aiohttp_auth import auth
|
|
||||||
|
|
||||||
from cbpi.api import *
|
|
||||||
|
|
||||||
|
|
||||||
class TranslationHttpEndpoint():
|
|
||||||
|
|
||||||
def __init__(self,cbpi):
|
|
||||||
self.cbpi = cbpi
|
|
||||||
self.cbpi.register(self, url_prefix="/translation")
|
|
||||||
|
|
||||||
|
|
||||||
@request_mapping(path="/missing_key", method="POST", auth_required=False)
|
|
||||||
async def missing_key(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Add missing translation key
|
|
||||||
tags:
|
|
||||||
- Translation
|
|
||||||
parameters:
|
|
||||||
- in: body
|
|
||||||
name: body
|
|
||||||
description: missing key data
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
locale:
|
|
||||||
type: string
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"204":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
data = await request.json()
|
|
||||||
await self.cbpi.translation.add_key(**data)
|
|
||||||
return web.Response(status=204)
|
|
||||||
|
|
||||||
@request_mapping(path="/", auth_required=False)
|
|
||||||
async def http_get_all(self, request):
|
|
||||||
"""
|
|
||||||
---
|
|
||||||
description: Get all translations
|
|
||||||
tags:
|
|
||||||
- Translation
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: successful operation
|
|
||||||
"""
|
|
||||||
|
|
||||||
return web.json_response(data=self.cbpi.translation.get_all())
|
|
|
@ -2,7 +2,7 @@
|
||||||
python3.7 setup.py clean --all
|
python3.7 setup.py clean --all
|
||||||
|
|
||||||
#build
|
#build
|
||||||
python setup.py sdist
|
python3 setup.py sdist
|
||||||
|
|
||||||
#Upload
|
#Upload
|
||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|
25
config/actor.json
Normal file
25
config/actor.json
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "9NkxVioA7FfZi6waegi246",
|
||||||
|
"name": "Manuel",
|
||||||
|
"props": {},
|
||||||
|
"state": {},
|
||||||
|
"type": "CustomActor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5hk68r3pFBe6JoRXzavLCA",
|
||||||
|
"name": "Actor 1",
|
||||||
|
"props": {},
|
||||||
|
"state": {},
|
||||||
|
"type": "CustomActor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "YgVFNsXncfMMoHD7U6TvP6",
|
||||||
|
"name": "111",
|
||||||
|
"props": {},
|
||||||
|
"state": {},
|
||||||
|
"type": "CustomActor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -244,6 +244,36 @@
|
||||||
"type": "Text",
|
"type": "Text",
|
||||||
"x": 615,
|
"x": 615,
|
||||||
"y": 280
|
"y": 280
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3a9e422f-8d55-4360-8f16-807f9a657988",
|
||||||
|
"name": "Steps",
|
||||||
|
"props": {
|
||||||
|
"width": "400"
|
||||||
|
},
|
||||||
|
"type": "Steps",
|
||||||
|
"x": 20,
|
||||||
|
"y": 430
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3be00e94-4e06-4a6b-9b8d-c832be73386a",
|
||||||
|
"name": "Led",
|
||||||
|
"props": {
|
||||||
|
"actor": 1
|
||||||
|
},
|
||||||
|
"type": "Led",
|
||||||
|
"x": 440,
|
||||||
|
"y": 215
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d896b230-8dab-4c33-b73a-1dd74e6de906",
|
||||||
|
"name": "Led",
|
||||||
|
"props": {
|
||||||
|
"actor": 1
|
||||||
|
},
|
||||||
|
"type": "Led",
|
||||||
|
"x": 625,
|
||||||
|
"y": 215
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pathes": [
|
"pathes": [
|
||||||
|
|
26
config/kettle.json
Normal file
26
config/kettle.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"agitator": "9NkxVioA7FfZi6waegi246",
|
||||||
|
"heater": "9NkxVioA7FfZi6waegi246",
|
||||||
|
"id": "gJ6jCupRmpxRsweY9nANTp",
|
||||||
|
"name": "Kettle 233312312",
|
||||||
|
"props": {},
|
||||||
|
"sensor": "TPpjzj9YXh6yYzvyJycmig",
|
||||||
|
"state": {},
|
||||||
|
"target_temp": 22,
|
||||||
|
"type": "CustomKettleLogic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"agitator": "9NkxVioA7FfZi6waegi246",
|
||||||
|
"heater": "9NkxVioA7FfZi6waegi246",
|
||||||
|
"id": "RMjMvwphxt3aiMrTnHbpcB",
|
||||||
|
"name": "Test",
|
||||||
|
"props": {},
|
||||||
|
"sensor": "TPpjzj9YXh6yYzvyJycmig",
|
||||||
|
"state": {},
|
||||||
|
"target_temp": 22,
|
||||||
|
"type": "CustomKettleLogic"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
21
config/sensor.json
Normal file
21
config/sensor.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "TPpjzj9YXh6yYzvyJycmig",
|
||||||
|
"name": "AMAZING22211111123123",
|
||||||
|
"props": {
|
||||||
|
"param1": "HALLO",
|
||||||
|
"param2": "Test"
|
||||||
|
},
|
||||||
|
"status": null,
|
||||||
|
"type": "CustomSensor2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2rAviwweTUY27Y8yZKftWA",
|
||||||
|
"name": "Testasdfasdf",
|
||||||
|
"props": {},
|
||||||
|
"status": null,
|
||||||
|
"type": "CustomSensor2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,31 +1,56 @@
|
||||||
{
|
{
|
||||||
"basic": {},
|
"basic": {
|
||||||
|
"name": "Weissbier"
|
||||||
|
},
|
||||||
"profile": [
|
"profile": [
|
||||||
{
|
{
|
||||||
"id": "eopJy6oxGqrNuRNtiAPXvN",
|
"id": "eopJy6oxGqrNuRNtiAPXvN",
|
||||||
"name": "AMAZING",
|
"name": "Step1",
|
||||||
"props": {
|
"props": {
|
||||||
"count": 5,
|
"Param1": "1",
|
||||||
|
"Param2": "HALLO",
|
||||||
|
"Param3": 1,
|
||||||
|
"count": 8,
|
||||||
"wohoo": 0
|
"wohoo": 0
|
||||||
},
|
},
|
||||||
"status": "P",
|
"status": "P",
|
||||||
"type": "CustomStep2"
|
"type": "CustomStep2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "duxvgLknKLjGYhdm9TKqUE",
|
"id": "hyXYDBUAENgwD7yNwaeLe7",
|
||||||
"name": "Manuel",
|
"name": "Step2",
|
||||||
"props": {
|
"props": {
|
||||||
"count": 5,
|
"Param1": "123",
|
||||||
|
"Param2": "Parameter2",
|
||||||
|
"Param3": 2,
|
||||||
|
"count": 0,
|
||||||
"wohoo": 0
|
"wohoo": 0
|
||||||
},
|
},
|
||||||
"status": "I",
|
"status": "I",
|
||||||
"type": "CustomStep2"
|
"type": "CustomStep2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "hyXYDBUAENgwD7yNwaeLe7",
|
"id": "iJHU9FgeGBtvDhraEHUoP2",
|
||||||
"name": "HALLO",
|
"name": "Step3",
|
||||||
"props": {
|
"props": {
|
||||||
"count": 5,
|
"Param1": 123,
|
||||||
|
"Param2": "HALLO",
|
||||||
|
"Param3": 2,
|
||||||
|
"Param5": 1,
|
||||||
|
"count": 0,
|
||||||
|
"wohoo": 0
|
||||||
|
},
|
||||||
|
"status": "I",
|
||||||
|
"type": "CustomStep2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "duxvgLknKLjGYhdm9TKqUE",
|
||||||
|
"name": "Step4",
|
||||||
|
"props": {
|
||||||
|
"Param1": "1222",
|
||||||
|
"Param2": "HELLO",
|
||||||
|
"Param3": 2,
|
||||||
|
"count": 0,
|
||||||
"wohoo": 0
|
"wohoo": 0
|
||||||
},
|
},
|
||||||
"status": "I",
|
"status": "I",
|
||||||
|
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
1
data.txt
1
data.txt
|
@ -1 +0,0 @@
|
||||||
{"people": [{"name": "Scott", "website": "stackabuse.com", "from": "Nebraska"}, {"name": "Larry", "website": "google.com", "from": "Michigan"}, {"name": "Tim", "website": "apple.com", "from": "Alabama"}]}
|
|
|
@ -1,40 +0,0 @@
|
||||||
aiohttp==3.7.3
|
|
||||||
aiohttp-auth==0.1.1
|
|
||||||
aiohttp-route-decorator==0.1.4
|
|
||||||
aiohttp-security==0.4.0
|
|
||||||
aiohttp-session==2.9.0
|
|
||||||
aiohttp-swagger==1.0.15
|
|
||||||
aiojobs==0.3.0
|
|
||||||
aiosqlite==0.16.0
|
|
||||||
asn1crypto==1.4.0
|
|
||||||
astroid==2.4.2
|
|
||||||
async-timeout==3.0.1
|
|
||||||
attrs==20.3.0
|
|
||||||
certifi==2020.12.5
|
|
||||||
cffi==1.14.4
|
|
||||||
chardet==3.0.4
|
|
||||||
cryptography==3.3.1
|
|
||||||
idna==2.10
|
|
||||||
isort==5.7.0
|
|
||||||
Jinja2==2.11.2
|
|
||||||
lazy-object-proxy==1.4.3
|
|
||||||
MarkupSafe==1.1.1
|
|
||||||
mccabe==0.6.1
|
|
||||||
multidict==4.7.6
|
|
||||||
numpy==1.19.4
|
|
||||||
pandas==1.2.0
|
|
||||||
pycparser==2.20
|
|
||||||
pyfiglet==0.8.post1
|
|
||||||
pylint==2.6.0
|
|
||||||
python-dateutil==2.8.1
|
|
||||||
pytz==2020.5
|
|
||||||
PyYAML==5.3.1
|
|
||||||
requests==2.25.1
|
|
||||||
six==1.15.0
|
|
||||||
ticket-auth==0.1.4
|
|
||||||
toml==0.10.2
|
|
||||||
typing-extensions==3.7.4.3
|
|
||||||
urllib3==1.26.2
|
|
||||||
voluptuous==0.12.1
|
|
||||||
wrapt==1.12.1
|
|
||||||
yarl==1.6.3
|
|
51
samples.txt
51
samples.txt
|
@ -1,51 +0,0 @@
|
||||||
function noop() {}
|
|
||||||
|
|
||||||
export default function (url, opts) {
|
|
||||||
opts = opts || {};
|
|
||||||
|
|
||||||
var ws, num=0, $={};
|
|
||||||
var max = opts.maxAttempts || Infinity;
|
|
||||||
|
|
||||||
$.open = function () {
|
|
||||||
ws = new WebSocket(url, opts.protocols || []);
|
|
||||||
|
|
||||||
ws.onmessage = opts.onmessage || noop;
|
|
||||||
|
|
||||||
ws.onopen = function (e) {
|
|
||||||
(opts.onopen || noop)(e);
|
|
||||||
num = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onclose = function (e) {
|
|
||||||
e.code === 1e3 || e.code === 1005 || $.reconnect(e);
|
|
||||||
(opts.onclose || noop)(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onerror = function (e) {
|
|
||||||
(e && e.code==='ECONNREFUSED') ? $.reconnect(e) : (opts.onerror || noop)(e);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
$.reconnect = function (e) {
|
|
||||||
(num++ < max) ? setTimeout(function () {
|
|
||||||
(opts.onreconnect || noop)(e);
|
|
||||||
$.open();
|
|
||||||
}, opts.timeout || 1e3) : (opts.onmaximum || noop)(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
$.json = function (x) {
|
|
||||||
ws.send(JSON.stringify(x));
|
|
||||||
};
|
|
||||||
|
|
||||||
$.send = function (x) {
|
|
||||||
ws.send(x);
|
|
||||||
};
|
|
||||||
|
|
||||||
$.close = function (x, y) {
|
|
||||||
ws.close(x || 1e3, y);
|
|
||||||
};
|
|
||||||
|
|
||||||
$.open(); // init
|
|
||||||
|
|
||||||
return $;
|
|
||||||
}
|
|
25
setup.py
25
setup.py
|
@ -1,7 +1,8 @@
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
from cbpi import __version__
|
||||||
|
|
||||||
setup(name='cbpi',
|
setup(name='cbpi',
|
||||||
version='4.0.0.5',
|
version=__version__,
|
||||||
description='CraftBeerPi',
|
description='CraftBeerPi',
|
||||||
author='Manuel Fritsch',
|
author='Manuel Fritsch',
|
||||||
author_email='manuel@craftbeerpi.com',
|
author_email='manuel@craftbeerpi.com',
|
||||||
|
@ -14,19 +15,21 @@ setup(name='cbpi',
|
||||||
'cbpi': ['*','*.txt', '*.rst', '*.yaml']},
|
'cbpi': ['*','*.txt', '*.rst', '*.yaml']},
|
||||||
|
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"aiohttp==3.4.4",
|
"aiohttp==3.7.3",
|
||||||
"aiohttp-auth==0.1.1",
|
"aiohttp-auth==0.1.1",
|
||||||
"aiohttp-route-decorator==0.1.4",
|
"aiohttp-route-decorator==0.1.4",
|
||||||
"aiohttp-security==0.4.0",
|
"aiohttp-security==0.4.0",
|
||||||
"aiohttp-session==2.7.0",
|
"aiohttp-session==2.9.0",
|
||||||
"aiohttp-swagger==1.0.5",
|
"aiohttp-swagger==1.0.15",
|
||||||
"aiojobs==0.2.2",
|
"aiojobs==0.3.0",
|
||||||
"aiosqlite==0.7.0",
|
"aiosqlite==0.16.0",
|
||||||
"cryptography==2.3.1",
|
"cryptography==3.3.1",
|
||||||
"requests==2.22.0",
|
"requests==2.25.1",
|
||||||
"voluptuous==0.11.5",
|
"voluptuous==0.12.1",
|
||||||
"pyfiglet==0.7.6",
|
"pyfiglet==0.8.post1",
|
||||||
'pandas==0.25.0'
|
'pandas==1.2.0',
|
||||||
|
'shortuuid==1.0.1',
|
||||||
|
'tabulate==0.8.7'
|
||||||
],
|
],
|
||||||
dependency_links=[
|
dependency_links=[
|
||||||
'https://testpypi.python.org/pypi'
|
'https://testpypi.python.org/pypi'
|
||||||
|
|
Loading…
Reference in a new issue