mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-25 00:18:17 +01:00
new step controller
This commit is contained in:
parent
8ced60706b
commit
05e08d0dc6
26 changed files with 1125 additions and 201 deletions
114
.vscode/.ropeproject/config.py
vendored
Normal file
114
.vscode/.ropeproject/config.py
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
# The default ``config.py``
|
||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
|
||||||
|
def set_prefs(prefs):
|
||||||
|
"""This function is called before opening the project"""
|
||||||
|
|
||||||
|
# Specify which files and folders to ignore in the project.
|
||||||
|
# Changes to ignored resources are not added to the history and
|
||||||
|
# VCSs. Also they are not returned in `Project.get_files()`.
|
||||||
|
# Note that ``?`` and ``*`` match all characters but slashes.
|
||||||
|
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
|
||||||
|
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
|
||||||
|
# '.svn': matches 'pkg/.svn' and all of its children
|
||||||
|
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
|
||||||
|
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
|
||||||
|
prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
|
||||||
|
'.hg', '.svn', '_svn', '.git', '.tox']
|
||||||
|
|
||||||
|
# Specifies which files should be considered python files. It is
|
||||||
|
# useful when you have scripts inside your project. Only files
|
||||||
|
# ending with ``.py`` are considered to be python files by
|
||||||
|
# default.
|
||||||
|
# prefs['python_files'] = ['*.py']
|
||||||
|
|
||||||
|
# Custom source folders: By default rope searches the project
|
||||||
|
# for finding source folders (folders that should be searched
|
||||||
|
# for finding modules). You can add paths to that list. Note
|
||||||
|
# that rope guesses project source folders correctly most of the
|
||||||
|
# time; use this if you have any problems.
|
||||||
|
# The folders should be relative to project root and use '/' for
|
||||||
|
# separating folders regardless of the platform rope is running on.
|
||||||
|
# 'src/my_source_folder' for instance.
|
||||||
|
# prefs.add('source_folders', 'src')
|
||||||
|
|
||||||
|
# You can extend python path for looking up modules
|
||||||
|
# prefs.add('python_path', '~/python/')
|
||||||
|
|
||||||
|
# Should rope save object information or not.
|
||||||
|
prefs['save_objectdb'] = True
|
||||||
|
prefs['compress_objectdb'] = False
|
||||||
|
|
||||||
|
# If `True`, rope analyzes each module when it is being saved.
|
||||||
|
prefs['automatic_soa'] = True
|
||||||
|
# The depth of calls to follow in static object analysis
|
||||||
|
prefs['soa_followed_calls'] = 0
|
||||||
|
|
||||||
|
# If `False` when running modules or unit tests "dynamic object
|
||||||
|
# analysis" is turned off. This makes them much faster.
|
||||||
|
prefs['perform_doa'] = True
|
||||||
|
|
||||||
|
# Rope can check the validity of its object DB when running.
|
||||||
|
prefs['validate_objectdb'] = True
|
||||||
|
|
||||||
|
# How many undos to hold?
|
||||||
|
prefs['max_history_items'] = 32
|
||||||
|
|
||||||
|
# Shows whether to save history across sessions.
|
||||||
|
prefs['save_history'] = True
|
||||||
|
prefs['compress_history'] = False
|
||||||
|
|
||||||
|
# Set the number spaces used for indenting. According to
|
||||||
|
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
|
||||||
|
# unit-tests use 4 spaces it is more reliable, too.
|
||||||
|
prefs['indent_size'] = 4
|
||||||
|
|
||||||
|
# Builtin and c-extension modules that are allowed to be imported
|
||||||
|
# and inspected by rope.
|
||||||
|
prefs['extension_modules'] = []
|
||||||
|
|
||||||
|
# Add all standard c-extensions to extension_modules list.
|
||||||
|
prefs['import_dynload_stdmods'] = True
|
||||||
|
|
||||||
|
# If `True` modules with syntax errors are considered to be empty.
|
||||||
|
# The default value is `False`; When `False` syntax errors raise
|
||||||
|
# `rope.base.exceptions.ModuleSyntaxError` exception.
|
||||||
|
prefs['ignore_syntax_errors'] = False
|
||||||
|
|
||||||
|
# If `True`, rope ignores unresolvable imports. Otherwise, they
|
||||||
|
# appear in the importing namespace.
|
||||||
|
prefs['ignore_bad_imports'] = False
|
||||||
|
|
||||||
|
# If `True`, rope will insert new module imports as
|
||||||
|
# `from <package> import <module>` by default.
|
||||||
|
prefs['prefer_module_from_imports'] = False
|
||||||
|
|
||||||
|
# If `True`, rope will transform a comma list of imports into
|
||||||
|
# multiple separate import statements when organizing
|
||||||
|
# imports.
|
||||||
|
prefs['split_imports'] = False
|
||||||
|
|
||||||
|
# If `True`, rope will remove all top-level import statements and
|
||||||
|
# reinsert them at the top of the module when making changes.
|
||||||
|
prefs['pull_imports_to_top'] = True
|
||||||
|
|
||||||
|
# If `True`, rope will sort imports alphabetically by module name instead
|
||||||
|
# of alphabetically by import statement, with from imports after normal
|
||||||
|
# imports.
|
||||||
|
prefs['sort_imports_alphabetically'] = False
|
||||||
|
|
||||||
|
# Location of implementation of
|
||||||
|
# rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
|
||||||
|
# case, you don't have to change this value, unless you're an rope expert.
|
||||||
|
# Change this value to inject you own implementations of interfaces
|
||||||
|
# listed in module rope.base.oi.type_hinting.providers.interfaces
|
||||||
|
# For example, you can add you own providers for Django Models, or disable
|
||||||
|
# the search type-hinting in a class hierarchy, etc.
|
||||||
|
prefs['type_hinting_factory'] = (
|
||||||
|
'rope.base.oi.type_hinting.factory.default_type_hinting_factory')
|
||||||
|
|
||||||
|
|
||||||
|
def project_opened(project):
|
||||||
|
"""This function is called after opening the project"""
|
||||||
|
# Do whatever you like here!
|
BIN
.vscode/.ropeproject/objectdb
vendored
Normal file
BIN
.vscode/.ropeproject/objectdb
vendored
Normal file
Binary file not shown.
|
@ -6,6 +6,7 @@ __all__ = ["CBPiActor",
|
||||||
"on_startup",
|
"on_startup",
|
||||||
"request_mapping",
|
"request_mapping",
|
||||||
"action",
|
"action",
|
||||||
|
"parameters",
|
||||||
"background_task",
|
"background_task",
|
||||||
"CBPiKettleLogic",
|
"CBPiKettleLogic",
|
||||||
"CBPiSimpleStep",
|
"CBPiSimpleStep",
|
||||||
|
@ -13,7 +14,8 @@ __all__ = ["CBPiActor",
|
||||||
"KettleException",
|
"KettleException",
|
||||||
"SensorException",
|
"SensorException",
|
||||||
"ActorException",
|
"ActorException",
|
||||||
"CBPiSensor"]
|
"CBPiSensor",
|
||||||
|
"CBPiStep"]
|
||||||
|
|
||||||
from cbpi.api.actor import *
|
from cbpi.api.actor import *
|
||||||
from cbpi.api.sensor import *
|
from cbpi.api.sensor import *
|
||||||
|
|
|
@ -2,7 +2,7 @@ from functools import wraps
|
||||||
|
|
||||||
from voluptuous import Schema
|
from voluptuous import Schema
|
||||||
|
|
||||||
__all__ = ["request_mapping", "on_startup", "on_event", "action", "background_task"]
|
__all__ = ["request_mapping", "on_startup", "on_event", "action", "background_task", "parameters"]
|
||||||
|
|
||||||
from aiohttp_auth import auth
|
from aiohttp_auth import auth
|
||||||
|
|
||||||
|
@ -73,6 +73,13 @@ def action(key, parameters):
|
||||||
|
|
||||||
return real_decorator
|
return real_decorator
|
||||||
|
|
||||||
|
def parameters(parameter):
|
||||||
|
def real_decorator(func):
|
||||||
|
func.cbpi_p = True
|
||||||
|
func.cbpi_parameters = parameter
|
||||||
|
return func
|
||||||
|
return real_decorator
|
||||||
|
|
||||||
def background_task(name, interval):
|
def background_task(name, interval):
|
||||||
def real_decorator(func):
|
def real_decorator(func):
|
||||||
func.background_task = True
|
func.background_task = True
|
||||||
|
|
|
@ -29,8 +29,6 @@ class Property(object):
|
||||||
'''
|
'''
|
||||||
def __init__(self, label, configurable=False, default_value=None, unit="", description=""):
|
def __init__(self, label, configurable=False, default_value=None, unit="", description=""):
|
||||||
'''
|
'''
|
||||||
Test
|
|
||||||
|
|
||||||
|
|
||||||
:param label:
|
:param label:
|
||||||
:param configurable:
|
:param configurable:
|
||||||
|
|
|
@ -3,7 +3,61 @@ import time
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from abc import abstractmethod, ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
class CBPiStep(metaclass=ABCMeta):
|
||||||
|
def __init__(self, cbpi, id, name, props) :
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.props = {"wohoo": 0, "count": 5, **props}
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
self.status = 0
|
||||||
|
self.running = False
|
||||||
|
self.stop_reason = None
|
||||||
|
self.pause = False
|
||||||
|
self.task = None
|
||||||
|
self._exception_count = 0
|
||||||
|
self._max_exceptions = 2
|
||||||
|
self.state_msg = "No state"
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return self.state_msg
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.stop_reason = "STOP"
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.running = True
|
||||||
|
self.stop_reason = None
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
self.stop_reason = "NEXT"
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def update(self, props):
|
||||||
|
await self.cbpi.step2.update_props(self.id, props)
|
||||||
|
|
||||||
|
async def run(self):
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
await self.execute()
|
||||||
|
except:
|
||||||
|
self._exception_count += 1
|
||||||
|
logging.error("Step has thrown exception")
|
||||||
|
if self._exception_count >= self._max_exceptions:
|
||||||
|
self.stop_reason = "MAX_EXCEPTIONS"
|
||||||
|
return (self.id, self.stop_reason)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
return (self.id, self.stop_reason)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def execute(self):
|
||||||
|
pass
|
||||||
|
|
||||||
class CBPiSimpleStep(metaclass=ABCMeta):
|
class CBPiSimpleStep(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
||||||
import json
|
import json
|
||||||
from cbpi.controller.crud_controller import CRUDController
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from cbpi.database.model import DashboardModel, DashboardContentModel
|
from cbpi.database.model import DashboardModel, DashboardContentModel
|
||||||
|
import os
|
||||||
|
|
||||||
class DashboardController(CRUDController):
|
class DashboardController(CRUDController):
|
||||||
|
|
||||||
|
@ -20,19 +20,23 @@ class DashboardController(CRUDController):
|
||||||
return dict(items=self.cache)
|
return dict(items=self.cache)
|
||||||
|
|
||||||
async def get_content(self, dashboard_id):
|
async def get_content(self, dashboard_id):
|
||||||
|
try:
|
||||||
with open('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id) as json_file:
|
with open('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id) as json_file:
|
||||||
data = json.load(json_file)
|
data = json.load(json_file)
|
||||||
return data
|
return data
|
||||||
|
except:
|
||||||
|
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)
|
||||||
print(data)
|
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
async def delete_content(self, content_id):
|
async def delete_content(self, dashboard_id):
|
||||||
await DashboardContentModel.delete(content_id)
|
if os.path.exists('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id):
|
||||||
|
os.remove('./config/dashboard/cbpi_dashboard_%s.json' % dashboard_id)
|
||||||
|
|
||||||
|
|
||||||
async def delete_dashboard(self, dashboard_id):
|
async def delete_dashboard(self, dashboard_id):
|
||||||
|
|
|
@ -11,6 +11,7 @@ from cbpi.utils.utils import load_config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PluginController():
|
class PluginController():
|
||||||
modules = {}
|
modules = {}
|
||||||
types = {}
|
types = {}
|
||||||
|
@ -34,18 +35,22 @@ class PluginController():
|
||||||
|
|
||||||
async def install(self, package_name):
|
async def install(self, package_name):
|
||||||
async def install(cbpi, plugins, package_name):
|
async def install(cbpi, plugins, package_name):
|
||||||
data = subprocess.check_output([sys.executable, "-m", "pip", "install", package_name])
|
data = subprocess.check_output(
|
||||||
|
[sys.executable, "-m", "pip", "install", package_name])
|
||||||
data = data.decode('UTF-8')
|
data = data.decode('UTF-8')
|
||||||
if package_name not in self.plugins:
|
if package_name not in self.plugins:
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
self.plugins[package_name] = dict(version="1.0", installation_date=now.strftime("%Y-%m-%d %H:%M:%S"))
|
self.plugins[package_name] = dict(
|
||||||
|
version="1.0", installation_date=now.strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
with open('./config/plugin_list.txt', 'w') as outfile:
|
with open('./config/plugin_list.txt', 'w') as outfile:
|
||||||
yaml.dump(self.plugins, outfile, default_flow_style=False)
|
yaml.dump(self.plugins, outfile, default_flow_style=False)
|
||||||
if data.startswith('Requirement already satisfied'):
|
if data.startswith('Requirement already satisfied'):
|
||||||
self.cbpi.notify(key="p", message="Plugin already installed ", type="warning")
|
self.cbpi.notify(
|
||||||
|
key="p", message="Plugin already installed ", type="warning")
|
||||||
else:
|
else:
|
||||||
|
|
||||||
self.cbpi.notify(key="p", message="Plugin installed ", type="success")
|
self.cbpi.notify(
|
||||||
|
key="p", message="Plugin installed ", type="success")
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get('http://localhost:2202/get/%s' % package_name) as resp:
|
async with session.get('http://localhost:2202/get/%s' % package_name) as resp:
|
||||||
|
@ -55,17 +60,20 @@ class PluginController():
|
||||||
await self.cbpi.job.start_job(install(self.cbpi, self.plugins, data["package_name"]), data["package_name"], "plugins_install")
|
await self.cbpi.job.start_job(install(self.cbpi, self.plugins, data["package_name"]), data["package_name"], "plugins_install")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.cbpi.notify(key="p", message="Failed to install Plugin %s " % package_name, type="danger")
|
self.cbpi.notify(
|
||||||
|
key="p", message="Failed to install Plugin %s " % package_name, type="danger")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def uninstall(self, package_name):
|
async def uninstall(self, package_name):
|
||||||
async def uninstall(cbpi, plugins, package_name):
|
async def uninstall(cbpi, plugins, package_name):
|
||||||
print("try to uninstall", package_name)
|
print("try to uninstall", package_name)
|
||||||
try:
|
try:
|
||||||
data = subprocess.check_output([sys.executable, "-m", "pip", "uninstall", "-y", package_name])
|
data = subprocess.check_output(
|
||||||
|
[sys.executable, "-m", "pip", "uninstall", "-y", package_name])
|
||||||
data = data.decode('UTF-8')
|
data = data.decode('UTF-8')
|
||||||
if data.startswith("Successfully uninstalled"):
|
if data.startswith("Successfully uninstalled"):
|
||||||
cbpi.notify(key="p", message="Plugin %s Uninstalled" % package_name, type="success")
|
cbpi.notify(key="p", message="Plugin %s Uninstalled" %
|
||||||
|
package_name, type="success")
|
||||||
else:
|
else:
|
||||||
cbpi.notify(key="p", message=data, type="success")
|
cbpi.notify(key="p", message=data, type="success")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -83,15 +91,17 @@ class PluginController():
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
logger.info("Trying to load plugin %s" % filename)
|
logger.info("Trying to load plugin %s" % filename)
|
||||||
data = load_config(os.path.join(this_directory, "../extension/%s/config.yaml" % filename))
|
data = load_config(os.path.join(
|
||||||
|
this_directory, "../extension/%s/config.yaml" % filename))
|
||||||
|
|
||||||
if (data.get("active") is True and data.get("version") == 4):
|
if (data.get("active") is True and data.get("version") == 4):
|
||||||
self.modules[filename] = import_module("cbpi.extension.%s" % (filename))
|
self.modules[filename] = import_module(
|
||||||
|
"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("Plugin %s is not supporting version 4" % filename)
|
logger.warning(
|
||||||
|
"Plugin %s is not supporting version 4" % filename)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
@ -132,9 +142,47 @@ class PluginController():
|
||||||
if issubclass(clazz, CBPiSimpleStep):
|
if issubclass(clazz, CBPiSimpleStep):
|
||||||
self.cbpi.step.types[name] = self._parse_props(clazz)
|
self.cbpi.step.types[name] = self._parse_props(clazz)
|
||||||
|
|
||||||
|
if issubclass(clazz, CBPiStep):
|
||||||
|
self.cbpi.step2.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)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_property_object(self, p):
|
||||||
|
if isinstance(p, Property.Number):
|
||||||
|
return {"label": p.label, "type": "number", "configurable": p.configurable, "description": p.description, "default_value": p.default_value}
|
||||||
|
elif isinstance(p, Property.Text):
|
||||||
|
return {"label": p.label, "type": "text", "configurable": p.configurable, "default_value": p.default_value, "description": p.description}
|
||||||
|
elif isinstance(p, Property.Select):
|
||||||
|
return {"label": p.label, "type": "select", "configurable": True, "options": p.options, "description": p.description}
|
||||||
|
elif isinstance(p, Property.Actor):
|
||||||
|
return {"label": p.label, "type": "actor", "configurable": p.configurable, "description": p.description}
|
||||||
|
elif isinstance(p, Property.Sensor):
|
||||||
|
return {"label": p.label, "type": "sensor", "configurable": p.configurable, "description": p.description}
|
||||||
|
elif isinstance(p, Property.Kettle):
|
||||||
|
return {"label": p.label, "type": "kettle", "configurable": p.configurable, "description": p.description}
|
||||||
|
|
||||||
|
def _parse_step_props(self, cls, name):
|
||||||
|
|
||||||
|
result = {"name": name, "class": cls,
|
||||||
|
"properties": [], "actions": []}
|
||||||
|
|
||||||
|
if hasattr(cls, "cbpi_parameters"):
|
||||||
|
parameters = []
|
||||||
|
for p in cls.cbpi_parameters:
|
||||||
|
parameters.append(self._parse_property_object(p))
|
||||||
|
result["properties"] = parameters
|
||||||
|
for method_name, method in cls.__dict__.items():
|
||||||
|
if hasattr(method, "action"):
|
||||||
|
key = method.__getattribute__("key")
|
||||||
|
parameters = []
|
||||||
|
for p in method.__getattribute__("parameters"):
|
||||||
|
parameters.append(self._parse_property_object(p))
|
||||||
|
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def _parse_props(self, cls):
|
def _parse_props(self, cls):
|
||||||
|
|
||||||
name = cls.__name__
|
name = cls.__name__
|
||||||
|
@ -142,7 +190,8 @@ class PluginController():
|
||||||
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
||||||
|
|
||||||
tmpObj = cls(cbpi=None, managed_fields=None)
|
tmpObj = cls(cbpi=None, managed_fields=None)
|
||||||
members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")]
|
members = [attr for attr in dir(tmpObj) if not callable(
|
||||||
|
getattr(tmpObj, attr)) and not attr.startswith("__")]
|
||||||
for m in members:
|
for m in members:
|
||||||
if isinstance(tmpObj.__getattribute__(m), Property.Number):
|
if isinstance(tmpObj.__getattribute__(m), Property.Number):
|
||||||
t = tmpObj.__getattribute__(m)
|
t = tmpObj.__getattribute__(m)
|
||||||
|
@ -158,18 +207,22 @@ class PluginController():
|
||||||
{"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description})
|
{"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description})
|
||||||
elif isinstance(tmpObj.__getattribute__(m), Property.Actor):
|
elif isinstance(tmpObj.__getattribute__(m), Property.Actor):
|
||||||
t = tmpObj.__getattribute__(m)
|
t = tmpObj.__getattribute__(m)
|
||||||
result["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description})
|
result["properties"].append(
|
||||||
|
{"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description})
|
||||||
elif isinstance(tmpObj.__getattribute__(m), Property.Sensor):
|
elif isinstance(tmpObj.__getattribute__(m), Property.Sensor):
|
||||||
t = tmpObj.__getattribute__(m)
|
t = tmpObj.__getattribute__(m)
|
||||||
result["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description})
|
result["properties"].append(
|
||||||
|
{"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description})
|
||||||
elif isinstance(tmpObj.__getattribute__(m), Property.Kettle):
|
elif isinstance(tmpObj.__getattribute__(m), Property.Kettle):
|
||||||
t = tmpObj.__getattribute__(m)
|
t = tmpObj.__getattribute__(m)
|
||||||
result["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description})
|
result["properties"].append(
|
||||||
|
{"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description})
|
||||||
|
|
||||||
for method_name, method in cls.__dict__.items():
|
for method_name, method in cls.__dict__.items():
|
||||||
if hasattr(method, "action"):
|
if hasattr(method, "action"):
|
||||||
key = method.__getattribute__("key")
|
key = method.__getattribute__("key")
|
||||||
parameters = method.__getattribute__("parameters")
|
parameters = method.__getattribute__("parameters")
|
||||||
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
|
result["actions"].append(
|
||||||
|
{"method": method_name, "label": key, "parameters": parameters})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -21,11 +21,8 @@ class SensorController(CRUDController):
|
||||||
async def init(self):
|
async def init(self):
|
||||||
'''
|
'''
|
||||||
This method initializes all actors during startup. It creates actor instances
|
This method initializes all actors during startup. It creates actor instances
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
await super(SensorController, self).init()
|
await super(SensorController, self).init()
|
||||||
for id, value in self.cache.items():
|
for id, value in self.cache.items():
|
||||||
await self.init_sensor(value)
|
await self.init_sensor(value)
|
||||||
|
@ -34,6 +31,9 @@ class SensorController(CRUDController):
|
||||||
return dict(items=self.cache,types=self.types)
|
return dict(items=self.cache,types=self.types)
|
||||||
|
|
||||||
async def init_sensor(self, sensor):
|
async def init_sensor(self, sensor):
|
||||||
|
|
||||||
|
|
||||||
|
print("INIT SENSOR")
|
||||||
if sensor.type in self.types:
|
if sensor.type in self.types:
|
||||||
cfg = sensor.config.copy()
|
cfg = sensor.config.copy()
|
||||||
cfg.update(dict(cbpi=self.cbpi, id=sensor.id, name=sensor.name))
|
cfg.update(dict(cbpi=self.cbpi, id=sensor.id, name=sensor.name))
|
||||||
|
|
251
cbpi/controller/step_controller_ng.py
Normal file
251
cbpi/controller/step_controller_ng.py
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ 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
|
||||||
|
@ -32,6 +33,7 @@ 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.controller.translation_controller import TranslationController
|
||||||
from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
|
from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
|
||||||
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
||||||
|
@ -94,9 +96,11 @@ class CraftBeerPi():
|
||||||
|
|
||||||
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)
|
||||||
|
@ -199,8 +203,8 @@ class CraftBeerPi():
|
||||||
print("SWAGGER.......")
|
print("SWAGGER.......")
|
||||||
setup_swagger(self.app,
|
setup_swagger(self.app,
|
||||||
description=long_description,
|
description=long_description,
|
||||||
title=self.static_config.get("name", "CraftBeerPi"),
|
title=self.static_config.get("name", "CraftBeerPi 4.0"),
|
||||||
api_version=self.static_config.get("version", ""),
|
api_version=self.static_config.get("version", "4.0"),
|
||||||
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:
|
||||||
|
@ -251,7 +255,7 @@ class CraftBeerPi():
|
||||||
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.step.init()
|
await self.step2.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)
|
||||||
|
|
|
@ -116,7 +116,7 @@ class CBPiEventBus(object):
|
||||||
futures = {}
|
futures = {}
|
||||||
|
|
||||||
|
|
||||||
self.logger.info("FIRE %s %s" % (topic, kwargs))
|
#self.logger.info("FIRE %s %s" % (topic, kwargs))
|
||||||
|
|
||||||
async def wait(futures):
|
async def wait(futures):
|
||||||
if(len(futures) > 0):
|
if(len(futures) > 0):
|
||||||
|
|
|
@ -38,6 +38,24 @@ class CustomStepCBPi(CBPiSimpleStep):
|
||||||
|
|
||||||
#self.cbpi.notify(key="step", message="HELLO FROM STEP")
|
#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):
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
@action(key="name", parameters=[Property.Number(label="Test", configurable=True)])
|
||||||
|
async def action(self, **kwargs):
|
||||||
|
print("HALLO")
|
||||||
|
|
||||||
|
async def execute(self):
|
||||||
|
|
||||||
|
print(self.props)
|
||||||
|
self.i += 1
|
||||||
|
print(self.i)
|
||||||
|
self.state_msg = "COUNT %s" % self.i
|
||||||
|
await self.update(self.props)
|
||||||
|
print("JETZT GEHTS LO")
|
||||||
|
#raise Exception("RROR")
|
||||||
|
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
|
@ -48,5 +66,5 @@ def setup(cbpi):
|
||||||
:param cbpi: the cbpi core
|
:param cbpi: the cbpi core
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
cbpi.plugin.register("CustomStep2", Step2)
|
||||||
cbpi.plugin.register("CustomStepCBPi", CustomStepCBPi)
|
cbpi.plugin.register("CustomStepCBPi", CustomStepCBPi)
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ConfigHttpEndpoints(HttpCrudEndpoints):
|
||||||
self.cbpi.register(self, "/config")
|
self.cbpi.register(self, "/config")
|
||||||
|
|
||||||
@request_mapping(path="/{name}/", method="PUT", auth_required=False)
|
@request_mapping(path="/{name}/", method="PUT", auth_required=False)
|
||||||
async def http_post(self, request) -> web.Response:
|
async def http_put(self, request) -> web.Response:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
---
|
---
|
||||||
|
@ -26,6 +26,15 @@ class ConfigHttpEndpoints(HttpCrudEndpoints):
|
||||||
description: "Parameter name"
|
description: "Parameter name"
|
||||||
required: true
|
required: true
|
||||||
type: "string"
|
type: "string"
|
||||||
|
- name: body
|
||||||
|
in: body
|
||||||
|
description: "Parameter Value"
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: successful operation
|
description: successful operation
|
||||||
|
|
|
@ -179,3 +179,26 @@ class DashBoardHttpEndpoints(HttpCrudEndpoints):
|
||||||
dashboard_id = int(request.match_info['id'])
|
dashboard_id = int(request.match_info['id'])
|
||||||
await self.cbpi.dashboard.add_content(dashboard_id, data)
|
await self.cbpi.dashboard.add_content(dashboard_id, data)
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/{id:\d+}/content", method="DELETE", auth_required=False)
|
||||||
|
async def delete_conent(self, request):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
description: Add Dashboard Content
|
||||||
|
tags:
|
||||||
|
- Dashboard
|
||||||
|
parameters:
|
||||||
|
- name: "id"
|
||||||
|
in: "path"
|
||||||
|
description: "Dashboard ID"
|
||||||
|
required: true
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: successful operation
|
||||||
|
"""
|
||||||
|
|
||||||
|
dashboard_id = int(request.match_info['id'])
|
||||||
|
await self.cbpi.dashboard.delete_content(dashboard_id)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
200
cbpi/http_endpoints/http_step2.py
Normal file
200
cbpi/http_endpoints/http_step2.py
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
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,7 +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=await self.cbpi.step.get_state(),
|
step=self.cbpi.step2.get_state(),
|
||||||
dashboard=self.cbpi.dashboard.get_state(),
|
dashboard=self.cbpi.dashboard.get_state(),
|
||||||
translations=self.cbpi.translation.get_all(),
|
translations=self.cbpi.translation.get_all(),
|
||||||
config=self.cbpi.config.get_state())
|
config=self.cbpi.config.get_state())
|
||||||
|
|
|
@ -4,8 +4,7 @@ from aiohttp.web import View
|
||||||
|
|
||||||
from . import create_scheduler
|
from . import create_scheduler
|
||||||
|
|
||||||
__all__ = ('setup', 'spawn', 'get_scheduler', 'get_scheduler_from_app',
|
__all__ = ('setup', 'spawn', 'get_scheduler', 'get_scheduler_from_app', 'atomic')
|
||||||
'atomic')
|
|
||||||
|
|
||||||
|
|
||||||
def get_scheduler(request):
|
def get_scheduler(request):
|
||||||
|
|
|
@ -1,196 +1,315 @@
|
||||||
{
|
{
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"id": "8bf7b72b-76e8-4c7a-86da-23f211d1942b",
|
"id": "db0c8199-6935-4c77-989a-28528b6743d7",
|
||||||
"name": "Kettle",
|
"name": "Kettle",
|
||||||
"props": {
|
"props": {
|
||||||
"heigth": "150",
|
"heigth": "150",
|
||||||
"width": "100"
|
"width": "100"
|
||||||
},
|
},
|
||||||
"type": "Kettle",
|
"type": "Kettle",
|
||||||
"x": 200,
|
|
||||||
"y": 115
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "78e5fe5a-6db8-4bd6-ba18-e67469cb1a0f",
|
|
||||||
"name": "Kettle",
|
|
||||||
"props": {
|
|
||||||
"heigth": "150",
|
|
||||||
"width": "100"
|
|
||||||
},
|
|
||||||
"type": "Kettle",
|
|
||||||
"x": 610,
|
|
||||||
"y": 115
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "0f45b8b5-8ebd-41b2-9bd2-a957f655b84c",
|
|
||||||
"name": "Kettle",
|
|
||||||
"props": {
|
|
||||||
"heigth": "150",
|
|
||||||
"width": "100"
|
|
||||||
},
|
|
||||||
"type": "Kettle",
|
|
||||||
"x": 410,
|
|
||||||
"y": 115
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "9d7d8ebf-ffad-4e35-96db-23d5b7f9c11c",
|
|
||||||
"name": "Sensor Data",
|
|
||||||
"props": {
|
|
||||||
"sensor": 1,
|
|
||||||
"unit": "\u00b0"
|
|
||||||
},
|
|
||||||
"type": "Sensor",
|
|
||||||
"x": 240,
|
|
||||||
"y": 230
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "97331778-eca2-4e35-b94b-3337763a372c",
|
|
||||||
"name": "Sensor Data",
|
|
||||||
"props": {
|
|
||||||
"sensor": 1,
|
|
||||||
"unit": "\u00b0"
|
|
||||||
},
|
|
||||||
"type": "Sensor",
|
|
||||||
"x": 450,
|
|
||||||
"y": 230
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f20b7ed4-cdc8-46c2-a01a-ac0c0eab3801",
|
|
||||||
"name": "Sensor Data",
|
|
||||||
"props": {
|
|
||||||
"sensor": 1,
|
|
||||||
"unit": "\u00b0"
|
|
||||||
},
|
|
||||||
"type": "Sensor",
|
|
||||||
"x": 655,
|
|
||||||
"y": 230
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "03eec665-ab3f-423b-bfb7-6faea856937b",
|
|
||||||
"name": "MashTun",
|
|
||||||
"props": {
|
|
||||||
"color": "#fff",
|
|
||||||
"size": "10"
|
|
||||||
},
|
|
||||||
"type": "Text",
|
|
||||||
"x": 205,
|
"x": 205,
|
||||||
"y": 120
|
"y": 155
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "9912ec53-71c7-4499-a1df-6466a4c02607",
|
"id": "35f8c20b-c801-4cf5-946c-29bcf88a989b",
|
||||||
"name": "Hot Liqour Tank",
|
"name": "Kettle",
|
||||||
|
"props": {
|
||||||
|
"heigth": "150",
|
||||||
|
"width": "100"
|
||||||
|
},
|
||||||
|
"type": "Kettle",
|
||||||
|
"x": 400,
|
||||||
|
"y": 155
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e62714ea-52c8-4544-af53-e7711fa3a087",
|
||||||
|
"name": "Kettle",
|
||||||
|
"props": {
|
||||||
|
"heigth": "150",
|
||||||
|
"width": "100"
|
||||||
|
},
|
||||||
|
"type": "Kettle",
|
||||||
|
"x": 585,
|
||||||
|
"y": 155
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d7f576b7-7fa7-4be7-8b31-68fef3b65777",
|
||||||
|
"name": "Mash",
|
||||||
"props": {
|
"props": {
|
||||||
"color": "#fff",
|
"color": "#fff",
|
||||||
"size": "10"
|
"size": "10"
|
||||||
},
|
},
|
||||||
"type": "Text",
|
"type": "Text",
|
||||||
"x": 415,
|
"x": 210,
|
||||||
"y": 120
|
"y": 135
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "4df11ebf-a8c9-4dc1-af8e-b6566bda0137",
|
"id": "36db0df9-922c-4cf6-8222-63f1eb34e22a",
|
||||||
|
"name": "HLT",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 405,
|
||||||
|
"y": 135
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7ae6a76b-712f-4d54-a661-7285b8f6d47b",
|
||||||
"name": "Boil",
|
"name": "Boil",
|
||||||
"props": {
|
"props": {
|
||||||
"color": "#fff",
|
"color": "#fff",
|
||||||
"size": "10"
|
"size": "10"
|
||||||
},
|
},
|
||||||
"type": "Text",
|
"type": "Text",
|
||||||
|
"x": 590,
|
||||||
|
"y": 140
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dfaad0f6-455c-4da6-9c82-789c6b36e046",
|
||||||
|
"name": "CraftBeerPi Brewery",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "26"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 205,
|
||||||
|
"y": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4d2c8dfe-61a9-433d-83a8-72f74d17e7e5",
|
||||||
|
"name": "Sensor Data",
|
||||||
|
"props": {
|
||||||
|
"sensor": 1,
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "Sensor",
|
||||||
|
"x": 245,
|
||||||
|
"y": 260
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "13a6b89d-50c7-4efb-b940-ec174e522314",
|
||||||
|
"name": "Sensor Data",
|
||||||
|
"props": {
|
||||||
|
"sensor": 1,
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "Sensor",
|
||||||
|
"x": 445,
|
||||||
|
"y": 260
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8d171952-791d-4f72-bfc9-dac8714b839f",
|
||||||
|
"name": "Sensor Data",
|
||||||
|
"props": {
|
||||||
|
"sensor": 1,
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "Sensor",
|
||||||
|
"x": 630,
|
||||||
|
"y": 260
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3963a344-8223-471f-aee6-5119e69f007f",
|
||||||
|
"name": "TargetTemp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"kettle": "1",
|
||||||
|
"size": "12",
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "TargetTemp",
|
||||||
|
"x": 215,
|
||||||
|
"y": 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "50333692-e956-4a8e-830f-934cd1d037c4",
|
||||||
|
"name": "TargetTemp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"kettle": "1",
|
||||||
|
"size": "12",
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "TargetTemp",
|
||||||
|
"x": 410,
|
||||||
|
"y": 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "28860d2d-f326-4375-a972-4e40a07bcf29",
|
||||||
|
"name": "Target Temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 215,
|
||||||
|
"y": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2f6129ab-61a5-4080-95d3-8832f3f8d57e",
|
||||||
|
"name": "Target Temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 410,
|
||||||
|
"y": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4b3f0ef9-61a8-4be2-9f6f-f954a04a77ce",
|
||||||
|
"name": "TargetTemp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"kettle": "1",
|
||||||
|
"size": "12",
|
||||||
|
"unit": "\u00b0"
|
||||||
|
},
|
||||||
|
"type": "TargetTemp",
|
||||||
|
"x": 595,
|
||||||
|
"y": 175
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9fc5f252-7f83-4eb6-89f6-99fd343502b8",
|
||||||
|
"name": "Target temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 595,
|
||||||
|
"y": 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3ec3e5d8-f82e-40c1-8c41-cb8286659d3b",
|
||||||
|
"name": "Led",
|
||||||
|
"props": {
|
||||||
|
"actor": 1
|
||||||
|
},
|
||||||
|
"type": "Led",
|
||||||
|
"x": 245,
|
||||||
|
"y": 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2e325539-6ed9-4e0d-b1dc-de860c47a1be",
|
||||||
|
"name": "Heater",
|
||||||
|
"props": {
|
||||||
|
"actor": 1
|
||||||
|
},
|
||||||
|
"type": "ActorButton",
|
||||||
|
"x": 210,
|
||||||
|
"y": 380
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "78b85989-c1bc-47e3-ad7b-0defeabb9bdc",
|
||||||
|
"name": "Pump",
|
||||||
|
"props": {
|
||||||
|
"actor": 2
|
||||||
|
},
|
||||||
|
"type": "ActorButton",
|
||||||
|
"x": 305,
|
||||||
|
"y": 380
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3c3f81d0-cdfd-4521-a2fe-2f039f17b583",
|
||||||
|
"name": "Current Temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 235,
|
||||||
|
"y": 280
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0ac051db-5550-4dac-a8ba-e3c1f131704b",
|
||||||
|
"name": "Current Temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
|
"x": 430,
|
||||||
|
"y": 280
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e9c833c2-6c87-4849-9ada-479ec95e79da",
|
||||||
|
"name": "Current Temp",
|
||||||
|
"props": {
|
||||||
|
"color": "#fff",
|
||||||
|
"size": "10"
|
||||||
|
},
|
||||||
|
"type": "Text",
|
||||||
"x": 615,
|
"x": 615,
|
||||||
"y": 120
|
"y": 280
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e51ca9a8-e911-42ea-ba19-ca21cfed72ce",
|
|
||||||
"name": "Current Temp",
|
|
||||||
"props": {
|
|
||||||
"color": "#fff",
|
|
||||||
"size": "10"
|
|
||||||
},
|
|
||||||
"type": "Text",
|
|
||||||
"x": 220,
|
|
||||||
"y": 215
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "6eb1d953-c579-4417-89ef-55cb472517a5",
|
|
||||||
"name": "Current Temp",
|
|
||||||
"props": {
|
|
||||||
"color": "#fff",
|
|
||||||
"size": "10"
|
|
||||||
},
|
|
||||||
"type": "Text",
|
|
||||||
"x": 435,
|
|
||||||
"y": 215
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "ad3087a4-5b8f-4ade-b665-4b2acbbaecc2",
|
|
||||||
"name": "Current Temp",
|
|
||||||
"props": {
|
|
||||||
"color": "#fff",
|
|
||||||
"size": "10"
|
|
||||||
},
|
|
||||||
"type": "Text",
|
|
||||||
"x": 635,
|
|
||||||
"y": 215
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "891eac86-3d81-4438-b9c4-65035c71e52f",
|
|
||||||
"name": "CraftBeerPi v4.0",
|
|
||||||
"props": {
|
|
||||||
"color": "#fff",
|
|
||||||
"size": "30"
|
|
||||||
},
|
|
||||||
"type": "Text",
|
|
||||||
"x": 200,
|
|
||||||
"y": 65
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pathes": [
|
"pathes": [
|
||||||
{
|
{
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
[
|
[
|
||||||
670,
|
305,
|
||||||
260
|
185
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
670,
|
405,
|
||||||
305
|
185
|
||||||
],
|
|
||||||
[
|
|
||||||
265,
|
|
||||||
305
|
|
||||||
],
|
|
||||||
[
|
|
||||||
265,
|
|
||||||
260
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"id": "74b4bf4d-3bb8-44d8-a50b-f27c915f6218"
|
"id": "49e7684e-21a3-4e0b-8e94-60f95abee80f"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
|
[
|
||||||
|
400,
|
||||||
|
275
|
||||||
|
],
|
||||||
[
|
[
|
||||||
305,
|
305,
|
||||||
230
|
275
|
||||||
],
|
|
||||||
[
|
|
||||||
410,
|
|
||||||
230
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"id": "c967d63c-7ec5-42b9-bbc3-e0d85b420670"
|
"id": "5ba909c1-49a9-46e5-a6d0-1d0350c37aa4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"coordinates": [
|
"coordinates": [
|
||||||
[
|
[
|
||||||
410,
|
255,
|
||||||
145
|
300
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
300,
|
255,
|
||||||
145
|
350
|
||||||
|
],
|
||||||
|
[
|
||||||
|
555,
|
||||||
|
350
|
||||||
|
],
|
||||||
|
[
|
||||||
|
555,
|
||||||
|
200
|
||||||
|
],
|
||||||
|
[
|
||||||
|
585,
|
||||||
|
200
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"id": "e5498af8-3086-4bee-b35b-085a13bbd2b2"
|
"id": "aed2d4d3-b99e-4af5-b8cf-d92d47721be4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"coordinates": [
|
||||||
|
[
|
||||||
|
685,
|
||||||
|
275
|
||||||
|
],
|
||||||
|
[
|
||||||
|
805,
|
||||||
|
275
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"id": "176fed29-56c2-4534-9cab-8c328d0e138c"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
35
config/step_data.json
Normal file
35
config/step_data.json
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"basic": {},
|
||||||
|
"profile": [
|
||||||
|
{
|
||||||
|
"id": "eopJy6oxGqrNuRNtiAPXvN",
|
||||||
|
"name": "AMAZING",
|
||||||
|
"props": {
|
||||||
|
"count": 5,
|
||||||
|
"wohoo": 0
|
||||||
|
},
|
||||||
|
"status": "P",
|
||||||
|
"type": "CustomStep2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "duxvgLknKLjGYhdm9TKqUE",
|
||||||
|
"name": "Manuel",
|
||||||
|
"props": {
|
||||||
|
"count": 5,
|
||||||
|
"wohoo": 0
|
||||||
|
},
|
||||||
|
"status": "I",
|
||||||
|
"type": "CustomStep2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hyXYDBUAENgwD7yNwaeLe7",
|
||||||
|
"name": "HALLO",
|
||||||
|
"props": {
|
||||||
|
"count": 5,
|
||||||
|
"wohoo": 0
|
||||||
|
},
|
||||||
|
"status": "I",
|
||||||
|
"type": "CustomStep2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
1
data.txt
Normal file
1
data.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"people": [{"name": "Scott", "website": "stackabuse.com", "from": "Nebraska"}, {"name": "Larry", "website": "google.com", "from": "Michigan"}, {"name": "Tim", "website": "apple.com", "from": "Alabama"}]}
|
19
sample.py
19
sample.py
|
@ -1,19 +0,0 @@
|
||||||
import datetime
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
from cbpi.utils.utils import load_config
|
|
||||||
|
|
||||||
package_name = "test222"
|
|
||||||
|
|
||||||
with open("./config/plugin_list.txt", 'rt') as f:
|
|
||||||
print(f)
|
|
||||||
plugins = yaml.load(f)
|
|
||||||
if plugins is None:
|
|
||||||
plugins = {}
|
|
||||||
|
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
|
|
||||||
plugins[package_name] = dict(version="1.0", installation_date=now.strftime("%Y-%m-%d %H:%M:%S"))
|
|
||||||
with open('./config/plugin_list.txt', 'w') as outfile:
|
|
||||||
yaml.dump(plugins, outfile, default_flow_style=False)
|
|
0
sampletest.py
Normal file
0
sampletest.py
Normal file
6
step_data.json
Normal file
6
step_data.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"basic": {},
|
||||||
|
"profile": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
46
tests/test_step_ng.py
Normal file
46
tests/test_step_ng.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import logging
|
||||||
|
from unittest import mock
|
||||||
|
import unittest
|
||||||
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
import pprint
|
||||||
|
import asyncio
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
||||||
|
pp = pprint.PrettyPrinter(indent=4)
|
||||||
|
|
||||||
|
class ActorTestCase(AioHTTPTestCase):
|
||||||
|
|
||||||
|
async def get_application(self):
|
||||||
|
self.cbpi = CraftBeerPi()
|
||||||
|
await self.cbpi.init_serivces()
|
||||||
|
return self.cbpi.app
|
||||||
|
'''
|
||||||
|
@unittest_run_loop
|
||||||
|
async def test_get_all(self):
|
||||||
|
resp = await self.client.get(path="/step2")
|
||||||
|
assert resp.status == 200
|
||||||
|
|
||||||
|
@unittest_run_loop
|
||||||
|
async def test_add_step(self):
|
||||||
|
resp = await self.client.post(path="/step2", json=dict(name="Manuel"))
|
||||||
|
data = await resp.json()
|
||||||
|
assert resp.status == 200
|
||||||
|
|
||||||
|
@unittest_run_loop
|
||||||
|
async def test_delete(self):
|
||||||
|
|
||||||
|
resp = await self.client.post(path="/step2", json=dict(name="Manuel"))
|
||||||
|
data = await resp.json()
|
||||||
|
assert resp.status == 200
|
||||||
|
resp = await self.client.delete(path="/step2/%s" % data["id"])
|
||||||
|
assert resp.status == 204
|
||||||
|
'''
|
||||||
|
|
||||||
|
@unittest_run_loop
|
||||||
|
async def test_move(self):
|
||||||
|
await self.cbpi.step2.resume()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in a new issue