mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-21 22:48:16 +01:00
config controller added
This commit is contained in:
parent
d5dac67c35
commit
28f87c6c3f
49 changed files with 1217 additions and 1927 deletions
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/core" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.7.1 virtualenv at ~/cbp42" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<project version="4">
|
||||
<component name="dataSourceStorageLocal">
|
||||
<data-source name="craftbeerpi.db" uuid="5067e7fe-480d-4433-bc40-f2d1c38362a2">
|
||||
<database-info product="SQLite" version="3.16.1" jdbc-version="2.1" driver-name="SQLiteJDBC" driver-version="native" />
|
||||
<database-info product="SQLite" version="3.16.1" jdbc-version="2.1" driver-name="SQLiteJDBC" driver-version="native" dbms="SQLITE" exact-version="3.16.1" />
|
||||
<case-sensitivity plain-identifiers="mixed" quoted-identifiers="mixed" />
|
||||
<secret-storage>master_key</secret-storage>
|
||||
<auth-required>false</auth-required>
|
||||
|
|
4
.idea/encodings.xml
Normal file
4
.idea/encodings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
8
.idea/markdown-exported-files.xml
Normal file
8
.idea/markdown-exported-files.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownExportedFiles">
|
||||
<htmlFiles />
|
||||
<imageFiles />
|
||||
<otherFiles />
|
||||
</component>
|
||||
</project>
|
72
.idea/markdown-navigator.xml
Normal file
72
.idea/markdown-navigator.xml
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownProjectSettings">
|
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true">
|
||||
<PanelProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
||||
</PanelProvider>
|
||||
</PreviewSettings>
|
||||
<ParserSettings gitHubSyntaxChange="false">
|
||||
<PegdownExtensions>
|
||||
<option name="ABBREVIATIONS" value="false" />
|
||||
<option name="ANCHORLINKS" value="true" />
|
||||
<option name="ASIDE" value="false" />
|
||||
<option name="ATXHEADERSPACE" value="true" />
|
||||
<option name="AUTOLINKS" value="true" />
|
||||
<option name="DEFINITIONS" value="false" />
|
||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
|
||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||
<option name="FOOTNOTES" value="false" />
|
||||
<option name="HARDWRAPS" value="false" />
|
||||
<option name="HTML_DEEP_PARSER" value="false" />
|
||||
<option name="INSERTED" value="false" />
|
||||
<option name="QUOTES" value="false" />
|
||||
<option name="RELAXEDHRULES" value="true" />
|
||||
<option name="SMARTS" value="false" />
|
||||
<option name="STRIKETHROUGH" value="true" />
|
||||
<option name="SUBSCRIPT" value="false" />
|
||||
<option name="SUPERSCRIPT" value="false" />
|
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
||||
<option name="TABLES" value="true" />
|
||||
<option name="TASKLISTITEMS" value="true" />
|
||||
<option name="TOC" value="false" />
|
||||
<option name="WIKILINKS" value="true" />
|
||||
</PegdownExtensions>
|
||||
<ParserOptions>
|
||||
<option name="COMMONMARK_LISTS" value="true" />
|
||||
<option name="DUMMY" value="false" />
|
||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
|
||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
||||
<option name="GITHUB_EMOJI_URL" value="false" />
|
||||
<option name="GITHUB_LISTS" value="false" />
|
||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||
</ParserOptions>
|
||||
</ParserSettings>
|
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false">
|
||||
<GeneratorProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
||||
</GeneratorProvider>
|
||||
<headerTop />
|
||||
<headerBottom />
|
||||
<bodyTop />
|
||||
<bodyBottom />
|
||||
</HtmlSettings>
|
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||
<StylesheetProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
||||
</StylesheetProvider>
|
||||
<ScriptProviders />
|
||||
<cssText />
|
||||
</CssSettings>
|
||||
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
|
||||
<LinkMapSettings>
|
||||
<textMaps />
|
||||
</LinkMapSettings>
|
||||
</component>
|
||||
</project>
|
3
.idea/markdown-navigator/profiles_settings.xml
Normal file
3
.idea/markdown-navigator/profiles_settings.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="MarkdownNavigator.ProfileManager">
|
||||
<settings default="" pdf-export="" />
|
||||
</component>
|
2176
.idea/workspace.xml
2176
.idea/workspace.xml
File diff suppressed because it is too large
Load diff
|
@ -7,3 +7,7 @@ port: 8080
|
|||
|
||||
username: cbpi
|
||||
password: 123
|
||||
|
||||
test:
|
||||
name: Manuel
|
||||
name2: Manuel
|
|
@ -1,6 +0,0 @@
|
|||
__all__ = ["CBPiActor", "CBPiExtension","Property", "PropertyType", "on_websocket_message", "on_mqtt_message", "on_event", "on_startup", "action", "background_task"]
|
||||
|
||||
from core.api.actor import *
|
||||
from core.api.extension import *
|
||||
from core.api.property import *
|
||||
from core.api.decorator import *
|
|
@ -1,48 +0,0 @@
|
|||
from abc import ABCMeta
|
||||
|
||||
__all__ = ["CBPiActor"]
|
||||
|
||||
import logging
|
||||
|
||||
from core.api.extension import CBPiExtension
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
class CBPiActor(CBPiExtension, metaclass=ABCMeta):
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
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
|
||||
|
||||
def off(self):
|
||||
|
||||
'''
|
||||
Code to switch the actor off
|
||||
|
||||
:return: None
|
||||
'''
|
||||
pass
|
||||
|
||||
def state(self):
|
||||
|
||||
'''
|
||||
Return the current actor state
|
||||
|
||||
:return:
|
||||
'''
|
||||
|
||||
pass
|
||||
|
||||
def reprJSON(self):
|
||||
return dict(state=True)
|
|
@ -1,96 +0,0 @@
|
|||
__all__ = ["request_mapping", "on_startup", "on_event", "on_mqtt_message", "on_websocket_message", "action", "background_task"]
|
||||
|
||||
from aiohttp_auth import auth
|
||||
|
||||
def composed(*decs):
|
||||
def deco(f):
|
||||
for dec in reversed(decs):
|
||||
f = dec(f)
|
||||
return f
|
||||
return deco
|
||||
|
||||
def request_mapping(path, name=None, method="GET", auth_required=True):
|
||||
|
||||
def on_http_request(path, name=None):
|
||||
def real_decorator(func):
|
||||
func.route = True
|
||||
func.path = path
|
||||
func.name = name
|
||||
func.method = method
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
if auth_required is True:
|
||||
return composed(
|
||||
on_http_request(path, name),
|
||||
auth.auth_required
|
||||
)
|
||||
else:
|
||||
return composed(
|
||||
on_http_request(path, name)
|
||||
)
|
||||
|
||||
def on_websocket_message(path, name=None):
|
||||
def real_decorator(func):
|
||||
func.ws = True
|
||||
func.key = path
|
||||
func.name = name
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
def on_event(topic):
|
||||
def real_decorator(func):
|
||||
func.eventbus = True
|
||||
func.topic = topic
|
||||
func.c = None
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
def action(key, parameters):
|
||||
def real_decorator(func):
|
||||
func.action = True
|
||||
|
||||
func.key = key
|
||||
func.parameters = parameters
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
def on_mqtt_message(topic):
|
||||
def real_decorator(func):
|
||||
func.mqtt = True
|
||||
func.topic = topic
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
|
||||
def background_task(name, interval):
|
||||
def real_decorator(func):
|
||||
func.background_task = True
|
||||
func.name = name
|
||||
func.interval = interval
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
|
||||
def on_startup(name, order=0):
|
||||
def real_decorator(func):
|
||||
func.on_startup = True
|
||||
func.name = name
|
||||
func.order = order
|
||||
return func
|
||||
|
||||
return real_decorator
|
||||
|
||||
|
||||
def entry_exit(f):
|
||||
def new_f():
|
||||
|
||||
f()
|
||||
|
||||
return new_f
|
|
@ -1,45 +0,0 @@
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
__all__ = ["CBPiExtension"]
|
||||
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
class CBPiExtension():
|
||||
|
||||
def init(self):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
|
||||
for a in kwds:
|
||||
|
||||
super(CBPiExtension, self).__setattr__(a, kwds.get(a))
|
||||
self.cbpi = kwds.get("cbpi")
|
||||
self.id = kwds.get("id")
|
||||
self.value = None
|
||||
self.__dirty = False
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
|
||||
if name != "_CBPiExtension__dirty":
|
||||
self.__dirty = True
|
||||
super(CBPiExtension, self).__setattr__(name, value)
|
||||
else:
|
||||
super(CBPiExtension, self).__setattr__(name, value)
|
||||
|
||||
def load_config(self):
|
||||
from core.utils.utils import load_config as load
|
||||
path = os.path.dirname(sys.modules[self.__class__.__module__].__file__)
|
||||
try:
|
||||
return load("%s/config.yaml" % path)
|
||||
except:
|
||||
logger.warning("Faild to load config %s/config.yaml" % path)
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
from core.api.extension import CBPiExtension
|
||||
|
||||
class CBPiKettleLogic(CBPiExtension):
|
||||
|
||||
'''
|
||||
Base Class for a Kettle logic.
|
||||
'''
|
||||
|
||||
def init(self):
|
||||
'''
|
||||
Code which will be executed when the logic is initialised. Needs to be overwritten by the implementing logic
|
||||
|
||||
:return: None
|
||||
'''
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
'''
|
||||
Code which will be executed when the logic is stopped. Needs to be overwritten by the implementing logic
|
||||
|
||||
|
||||
:return: None
|
||||
'''
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
This method is running as background process when logic is started.
|
||||
Typically a while loop responsible that the method keeps running
|
||||
|
||||
while self.running:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
:return: None
|
||||
'''
|
||||
|
||||
pass
|
|
@ -1,113 +0,0 @@
|
|||
__all__ = ["PropertyType", "Property"]
|
||||
|
||||
class PropertyType(object):
|
||||
pass
|
||||
|
||||
class Property(object):
|
||||
class Select(PropertyType):
|
||||
|
||||
'''
|
||||
Select Property. The user can select value from list set as options parameter
|
||||
'''
|
||||
|
||||
def __init__(self, label, options, description=""):
|
||||
'''
|
||||
|
||||
:param label:
|
||||
:param options:
|
||||
:param description:
|
||||
'''
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.options = options
|
||||
self.description = description
|
||||
|
||||
class Number(PropertyType):
|
||||
|
||||
'''
|
||||
The user can set a number value
|
||||
'''
|
||||
def __init__(self, label, configurable=False, default_value=None, unit="", description=""):
|
||||
'''
|
||||
Test
|
||||
|
||||
|
||||
:param label:
|
||||
:param configurable:
|
||||
:param default_value:
|
||||
:param unit:
|
||||
:param description:
|
||||
'''
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Text(PropertyType):
|
||||
|
||||
'''
|
||||
The user can set a text value
|
||||
'''
|
||||
def __init__(self, label, configurable=False, default_value="", description=""):
|
||||
'''
|
||||
|
||||
:param label:
|
||||
:param configurable:
|
||||
:param default_value:
|
||||
:param description:
|
||||
'''
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = configurable
|
||||
self.default_value = default_value
|
||||
self.description = description
|
||||
|
||||
class Actor(PropertyType):
|
||||
|
||||
'''
|
||||
The user select an actor which is available in the system. The value of this variable will be the actor id
|
||||
'''
|
||||
def __init__(self, label, description=""):
|
||||
'''
|
||||
|
||||
:param label:
|
||||
:param description:
|
||||
'''
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Sensor(PropertyType):
|
||||
'''
|
||||
The user select a sensor which is available in the system. The value of this variable will be the sensor id
|
||||
'''
|
||||
|
||||
def __init__(self, label, description=""):
|
||||
'''
|
||||
|
||||
:param label:
|
||||
:param description:
|
||||
'''
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
||||
|
||||
class Kettle(PropertyType):
|
||||
'''
|
||||
The user select a kettle which is available in the system. The value of this variable will be the kettle id
|
||||
'''
|
||||
|
||||
def __init__(self, label, description=""):
|
||||
'''
|
||||
|
||||
:param label:
|
||||
:param description:
|
||||
'''
|
||||
|
||||
PropertyType.__init__(self)
|
||||
self.label = label
|
||||
self.configurable = True
|
||||
self.description = description
|
|
@ -1,9 +0,0 @@
|
|||
from core.api.extension import CBPiExtension
|
||||
|
||||
class CBPiSensor(CBPiExtension):
|
||||
|
||||
async def run(self, cbpi):
|
||||
print("RUN NOT IMPLEMENTED")
|
||||
|
||||
def state(self):
|
||||
pass
|
134
core/api/step.py
134
core/api/step.py
|
@ -1,134 +0,0 @@
|
|||
import time
|
||||
import asyncio
|
||||
import logging
|
||||
from abc import abstractmethod,ABCMeta
|
||||
|
||||
|
||||
class CBPiSimpleStep(metaclass=ABCMeta):
|
||||
|
||||
__dirty = False
|
||||
managed_fields = []
|
||||
_interval = 1
|
||||
_max_exceptions = 2
|
||||
_exception_count = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
for a in kwargs:
|
||||
super(CBPiSimpleStep, self).__setattr__(a, kwargs.get(a))
|
||||
self.id = kwargs.get("id")
|
||||
self.is_stopped = False
|
||||
self.is_next = False
|
||||
self.start = time.time()
|
||||
|
||||
def running(self):
|
||||
'''
|
||||
Method checks if the step should continue running.
|
||||
The method will return False if the step is requested to stop or the next step should start
|
||||
|
||||
:return: True if the step is running. Otherwise False.
|
||||
'''
|
||||
if self.is_next is True:
|
||||
return False
|
||||
|
||||
if self.is_stopped is True:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def run(self):
|
||||
|
||||
'''
|
||||
This method in running in the background. It invokes the run_cycle method in the configured interval
|
||||
It checks if a managed variable was modified in the last exection cycle. If yes, the method will persisit the new value of the
|
||||
managed property
|
||||
|
||||
:return: None
|
||||
'''
|
||||
|
||||
while self.running():
|
||||
try:
|
||||
await self.run_cycle()
|
||||
except Exception as e:
|
||||
logging.exception("CBPiSimpleStep Error")
|
||||
self._exception_count = self._exception_count + 1
|
||||
if self._exception_count == self._max_exceptions:
|
||||
self.logger.error("Step Exception limit exceeded. Stopping Step")
|
||||
self.stop()
|
||||
print("INTER",self._interval)
|
||||
await asyncio.sleep(self._interval)
|
||||
|
||||
if self.is_dirty():
|
||||
# Now we have to store the managed props
|
||||
state = {}
|
||||
for field in self.managed_fields:
|
||||
state[field] = self.__getattribute__(field)
|
||||
#step_controller.model.update_step_state(step_controller.current_step.id, state)
|
||||
print("STATE",state)
|
||||
await self.cbpi.step.model.update_step_state(self.id, state)
|
||||
|
||||
self.reset_dirty()
|
||||
|
||||
@abstractmethod
|
||||
async def run_cycle(self):
|
||||
'''
|
||||
This method is executed in the defined interval.
|
||||
That the place to put your step logic.
|
||||
The method need to be overwritten in the Ccstom step implementaion
|
||||
|
||||
:return: None
|
||||
'''
|
||||
|
||||
print("NOTING IMPLEMENTED")
|
||||
pass
|
||||
|
||||
def next(self):
|
||||
|
||||
'''
|
||||
Request to stop the the step
|
||||
|
||||
:return: None
|
||||
'''
|
||||
|
||||
self.is_next = True
|
||||
|
||||
def stop(self):
|
||||
'''
|
||||
Request to stop the step
|
||||
|
||||
:return: None
|
||||
'''
|
||||
self.is_stopped = True
|
||||
|
||||
def reset(self):
|
||||
'''
|
||||
Reset the step. This method needs to be overwritten by the custom step implementation
|
||||
|
||||
:return: None
|
||||
'''
|
||||
pass
|
||||
|
||||
def is_dirty(self):
|
||||
|
||||
'''
|
||||
Check if a managed variable has a new value
|
||||
|
||||
:return: True if at least one managed variable has a new value assigend. Otherwise False
|
||||
'''
|
||||
return self.__dirty
|
||||
|
||||
def reset_dirty(self):
|
||||
'''
|
||||
Reset the dirty flag
|
||||
|
||||
:return:
|
||||
'''
|
||||
|
||||
self.__dirty = False
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name != "_Step__dirty" and name in self.managed_fields:
|
||||
self.__dirty = True
|
||||
super(CBPiSimpleStep, self).__setattr__(name, value)
|
||||
else:
|
||||
super(CBPiSimpleStep, self).__setattr__(name, value)
|
|
@ -1,11 +1,13 @@
|
|||
import json
|
||||
import logging
|
||||
from asyncio import Future
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from core.api.decorator import on_event, request_mapping
|
||||
from cbpi_api import *
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.model import ActorModel
|
||||
from core.http_endpoints.http_api import HttpAPI
|
||||
from utils.encoder import ComplexEncoder
|
||||
|
||||
|
||||
class ActorHttp(HttpAPI):
|
||||
|
@ -17,11 +19,11 @@ class ActorHttp(HttpAPI):
|
|||
:return:
|
||||
"""
|
||||
id = int(request.match_info['id'])
|
||||
result = await self.cbpi.bus.fire2(topic="actor/%s/switch/on" % id, id=id, power=99)
|
||||
print(result.timeout)
|
||||
result = await self.cbpi.bus.fire(topic="actor/%s/switch/on" % id, id=id, power=99)
|
||||
|
||||
|
||||
for key, value in result.results.items():
|
||||
print(key, value.result)
|
||||
pass
|
||||
return web.Response(status=204)
|
||||
|
||||
|
||||
|
@ -42,7 +44,7 @@ class ActorHttp(HttpAPI):
|
|||
:return:
|
||||
"""
|
||||
id = int(request.match_info['id'])
|
||||
print("ID", id)
|
||||
|
||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % id, id=id)
|
||||
return web.Response(status=204)
|
||||
|
||||
|
@ -57,11 +59,16 @@ class ActorController(ActorHttp, CRUDController):
|
|||
super(ActorController, self).__init__(cbpi)
|
||||
self.cbpi = cbpi
|
||||
self.state = False;
|
||||
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.cbpi.register(self, "/actor")
|
||||
self.types = {}
|
||||
self.actors = {}
|
||||
|
||||
def info(self):
|
||||
|
||||
return json.dumps(dict(name="ActorController", types=self.types), cls=ComplexEncoder)
|
||||
|
||||
|
||||
async def init(self):
|
||||
'''
|
||||
This method initializes all actors during startup. It creates actor instances
|
||||
|
@ -104,7 +111,7 @@ class ActorController(ActorHttp, CRUDController):
|
|||
|
||||
id = int(id)
|
||||
if id in self.cache:
|
||||
print("POWER ON")
|
||||
self.logger.debug("ON %s" % id)
|
||||
actor = self.cache[id].instance
|
||||
await self.cbpi.bus.fire("actor/%s/on/ok" % id)
|
||||
actor.on(power)
|
||||
|
@ -122,6 +129,7 @@ class ActorController(ActorHttp, CRUDController):
|
|||
:return:
|
||||
'''
|
||||
|
||||
self.logger.debug("TOGGLE %s" % id)
|
||||
id = int(id)
|
||||
if id in self.cache:
|
||||
actor = self.cache[id].instance
|
||||
|
@ -141,6 +149,7 @@ class ActorController(ActorHttp, CRUDController):
|
|||
:param kwargs:
|
||||
"""
|
||||
|
||||
self.logger.debug("OFF %s" % id)
|
||||
id = int(id)
|
||||
|
||||
if id in self.cache:
|
||||
|
|
|
@ -1,8 +1,36 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from aiohttp import web
|
||||
from cbpi_api import request_mapping
|
||||
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.model import ConfigModel
|
||||
from utils import load_config, json_dumps
|
||||
from cbpi_api.config import ConfigType
|
||||
|
||||
class ConfigHTTPController():
|
||||
@request_mapping(path="/{name}/", method="POST", auth_required=False)
|
||||
async def http_post(self, request) -> web.Response:
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
name = request.match_info['name']
|
||||
data = await request.json()
|
||||
print(data)
|
||||
await self.set(name=name, value=data.get("value"))
|
||||
return web.Response(status=204)
|
||||
|
||||
class ConfigController(CRUDController):
|
||||
@request_mapping(path="/", auth_required=False)
|
||||
async def http_get_all(self, request) -> web.Response:
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
return web.json_response(self.cache, dumps=json_dumps)
|
||||
|
||||
class ConfigController(ConfigHTTPController):
|
||||
|
||||
'''
|
||||
The main actor controller
|
||||
|
@ -10,9 +38,35 @@ class ConfigController(CRUDController):
|
|||
model = ConfigModel
|
||||
|
||||
def __init__(self, cbpi):
|
||||
super(ConfigController, self).__init__(cbpi)
|
||||
self.cache = {}
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.cbpi = cbpi
|
||||
|
||||
self.cbpi.register(self, "/config")
|
||||
|
||||
async def init(self):
|
||||
this_directory = os.path.dirname(__file__)
|
||||
self.static = load_config(os.path.join(this_directory, '../../config/config.yaml'))
|
||||
items = await self.model.get_all()
|
||||
for key, value in items.items():
|
||||
self.cache[value.name] = value
|
||||
|
||||
|
||||
async def get(self, name, default=None):
|
||||
self.logger.info("GET CONFIG VALUE %s (default %s)" % (name,default))
|
||||
if name in self.cache and self.cache[name].value is not None:
|
||||
return self.cache[name].value
|
||||
else:
|
||||
return default
|
||||
|
||||
async def set(self, name, value):
|
||||
self.logger.debug("SET %s = %s" % (name, value))
|
||||
if name in self.cache:
|
||||
|
||||
self.cache[name].value = value
|
||||
m = await self.model.update(**self.cache[name].__dict__)
|
||||
await self.cbpi.bus.fire(topic="config/%s/update" % name, name=name, value=value)
|
||||
|
||||
|
||||
async def add(self, name, value, type: ConfigType, description, options=None):
|
||||
m = await self.model.insert(name=name, value=value, type=type.value, description=description, options=options)
|
||||
await self.cbpi.bus.fire(topic="config/%s/add" % name, name=name, value=value)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import json
|
||||
import pprint
|
||||
from abc import abstractmethod,ABCMeta
|
||||
|
||||
from core.utils.encoder import ComplexEncoder
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class CRUDController(metaclass=ABCMeta):
|
||||
|
@ -141,10 +138,10 @@ class CRUDController(metaclass=ABCMeta):
|
|||
await self._post_delete_callback(id)
|
||||
try:
|
||||
if self.caching is True:
|
||||
print("DELTE FROM ACHE")
|
||||
|
||||
del self.cache[int(id)]
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
pass
|
||||
pprint.pprint(self.cache)
|
||||
await self.cbpi.bus.fire(topic="actor/%s/deleted" % id, id=id)
|
||||
|
|
|
@ -2,7 +2,8 @@ import re
|
|||
|
||||
from aiohttp import web
|
||||
|
||||
from core.api import request_mapping, on_event
|
||||
|
||||
from cbpi_api import *
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.model import KettleModel
|
||||
from core.http_endpoints.http_api import HttpAPI
|
||||
|
@ -84,7 +85,7 @@ class KettleController(CRUDController):
|
|||
kettle = self.cache[int(kid)]
|
||||
kettle.instance = None
|
||||
|
||||
print("STOP KETTLE LOGIC", kid)
|
||||
|
||||
|
||||
@on_event(topic="kettle/+/automatic")
|
||||
async def handle_automtic_event(self, id, **kwargs):
|
||||
|
@ -97,9 +98,9 @@ class KettleController(CRUDController):
|
|||
:return: None
|
||||
'''
|
||||
id = int(id)
|
||||
print("WOOOHO", type(id), self.cache)
|
||||
|
||||
if id in self.cache:
|
||||
print("id", id)
|
||||
|
||||
kettle = self.cache[id]
|
||||
|
||||
if hasattr(kettle, "instance") is False:
|
||||
|
@ -111,7 +112,7 @@ class KettleController(CRUDController):
|
|||
cfg = kettle.config.copy()
|
||||
cfg.update(dict(cbpi=self.cbpi))
|
||||
kettle.instance = clazz(**cfg)
|
||||
print("START LOGIC")
|
||||
|
||||
await self.cbpi.start_job(kettle.instance.run(), "Kettle_logic_%s" % kettle.id, "kettle_logic%s"%id)
|
||||
else:
|
||||
kettle.instance.running = False
|
||||
|
@ -120,7 +121,7 @@ class KettleController(CRUDController):
|
|||
|
||||
def _is_logic_running(self, kettle_id):
|
||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
||||
print("JOB KETTLE RUNNING", scheduler.is_running("Kettle_logic_%s"%kettle_id))
|
||||
|
||||
|
||||
async def heater_on(self, id):
|
||||
'''
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from core.api.decorator import on_event
|
||||
|
||||
from cbpi_api import *
|
||||
|
||||
class NotificationController():
|
||||
'''
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import imp
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from importlib import import_module
|
||||
from pprint import pprint
|
||||
|
||||
|
@ -7,17 +10,11 @@ import aiohttp
|
|||
import yaml
|
||||
from aiohttp import web
|
||||
|
||||
from core.api.actor import CBPiActor
|
||||
from core.api.decorator import request_mapping
|
||||
from core.api.extension import CBPiExtension
|
||||
from core.api.kettle_logic import CBPiKettleLogic
|
||||
from core.api.property import Property
|
||||
from core.api.sensor import CBPiSensor
|
||||
from core.api.step import CBPiSimpleStep
|
||||
from cbpi_api import *
|
||||
from core.utils.utils import load_config, json_dumps
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginController():
|
||||
|
||||
|
@ -64,6 +61,18 @@ class PluginController():
|
|||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
def load_plugins_from_evn(self):
|
||||
|
||||
|
||||
plugins = ["cbpi-actor"]
|
||||
|
||||
|
||||
for p in plugins:
|
||||
|
||||
self.modules[p] = import_module(p)
|
||||
self.modules[p].setup(self.cbpi)
|
||||
|
||||
|
||||
@request_mapping(path="/plugins", method="GET", auth_required=False)
|
||||
async def get_plugins(self, request):
|
||||
"""
|
||||
|
@ -90,7 +99,7 @@ class PluginController():
|
|||
:param clazz: actor class
|
||||
:return: None
|
||||
'''
|
||||
print("REGISTER", name, clazz)
|
||||
|
||||
if issubclass(clazz, CBPiActor):
|
||||
self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
|
||||
|
||||
|
@ -103,12 +112,12 @@ class PluginController():
|
|||
|
||||
if issubclass(clazz, CBPiSimpleStep):
|
||||
self.cbpi.step.types[name] = self._parse_props(clazz)
|
||||
print(self.cbpi.step.types)
|
||||
|
||||
if issubclass(clazz, CBPiExtension):
|
||||
self.c = clazz(self.cbpi)
|
||||
|
||||
def _parse_props(self, cls):
|
||||
print("PARSE", cls)
|
||||
|
||||
name = cls.__name__
|
||||
|
||||
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
||||
|
@ -143,5 +152,5 @@ class PluginController():
|
|||
key = method.__getattribute__("key")
|
||||
parameters = method.__getattribute__("parameters")
|
||||
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
|
||||
pprint(result)
|
||||
|
||||
return result
|
|
@ -1,10 +1,10 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
from core.utils.encoder import ComplexEncoder
|
||||
from core.job.aiohttp import get_scheduler_from_app
|
||||
|
||||
from core.api.decorator import background_task
|
||||
from cbpi_api import *
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.model import SensorModel
|
||||
from core.http_endpoints.http_api import HttpAPI
|
||||
|
@ -22,7 +22,9 @@ class SensorController(CRUDController, HttpAPI):
|
|||
|
||||
self.sensors = {}
|
||||
|
||||
def info(self):
|
||||
|
||||
return json.dumps(dict(name="SensorController", types=self.types), cls=ComplexEncoder)
|
||||
|
||||
async def init(self):
|
||||
'''
|
||||
|
@ -31,9 +33,9 @@ class SensorController(CRUDController, HttpAPI):
|
|||
:return:
|
||||
'''
|
||||
await super(SensorController, self).init()
|
||||
print("INIT SENSOR")
|
||||
|
||||
for name, clazz in self.types.items():
|
||||
print("Type", name)
|
||||
pass
|
||||
|
||||
for id, value in self.cache.items():
|
||||
if value.type in self.types:
|
||||
|
@ -43,7 +45,7 @@ class SensorController(CRUDController, HttpAPI):
|
|||
self.cache[id].instance = clazz(**cfg)
|
||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
||||
self.cache[id].instance.job = await scheduler.spawn(self.cache[id].instance.run(self.cbpi), value.name, "sensor")
|
||||
print("------------")
|
||||
|
||||
|
||||
async def get_value(self, id):
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
|||
|
||||
import time
|
||||
from aiohttp import web
|
||||
from core.api import on_event, request_mapping
|
||||
from cbpi_api import *
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.model import StepModel
|
||||
from core.http_endpoints.http_api import HttpAPI
|
||||
|
@ -36,7 +36,7 @@ class StepController(HttpAPI, CRUDController):
|
|||
:return:
|
||||
'''
|
||||
await super(StepController, self).init()
|
||||
print("INIT LAST STEP")
|
||||
|
||||
await self.init_after_startup()
|
||||
|
||||
async def init_after_startup(self):
|
||||
|
@ -45,14 +45,14 @@ class StepController(HttpAPI, CRUDController):
|
|||
|
||||
|
||||
if step is not None:
|
||||
print("INIT LAST STEP", step.__dict__)
|
||||
|
||||
# get the type
|
||||
print(self.types)
|
||||
|
||||
step_type = self.types.get(step.type)
|
||||
|
||||
if step_type is None:
|
||||
# step type not found. cant restart step
|
||||
print("STEP TYPE NONT FOUND")
|
||||
|
||||
return
|
||||
|
||||
if step.stepstate is not None:
|
||||
|
@ -201,10 +201,10 @@ class StepController(HttpAPI, CRUDController):
|
|||
:return:
|
||||
'''
|
||||
|
||||
print("IS SHUTODONW", self.cbpi.shutdown)
|
||||
|
||||
if self.cbpi.shutdown:
|
||||
return
|
||||
print("JOB DONE STEP")
|
||||
|
||||
self.cache[self.current_step.id].state = "D"
|
||||
step_id = self.current_step.id
|
||||
self.current_step = None
|
||||
|
@ -214,7 +214,7 @@ class StepController(HttpAPI, CRUDController):
|
|||
|
||||
|
||||
def _get_manged_fields_as_array(self, type_cfg):
|
||||
print("tYPE", type_cfg)
|
||||
|
||||
result = []
|
||||
for f in type_cfg.get("properties"):
|
||||
result.append(f.get("name"))
|
||||
|
@ -236,7 +236,7 @@ class StepController(HttpAPI, CRUDController):
|
|||
inactive = await self.model.get_by_state("I")
|
||||
active = await self.model.get_by_state("A")
|
||||
|
||||
print("STEPES", inactive, active)
|
||||
|
||||
|
||||
if active is not None:
|
||||
active.state = 'D'
|
||||
|
|
|
@ -2,7 +2,7 @@ import datetime
|
|||
from aiohttp import web
|
||||
from aiojobs.aiohttp import get_scheduler_from_app
|
||||
|
||||
from core.api.decorator import request_mapping
|
||||
from cbpi_api import *
|
||||
|
||||
|
||||
class SystemController():
|
||||
|
@ -28,9 +28,7 @@ class SystemController():
|
|||
result = []
|
||||
for j in scheduler:
|
||||
try:
|
||||
print(datetime.datetime.fromtimestamp(
|
||||
j.start_time
|
||||
).strftime('%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
result.append(dict(name=j.name, type=j.type, time=j.start_time))
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -26,8 +26,11 @@ from core.eventbus import EventBus
|
|||
from core.http_endpoints.http_login import Login
|
||||
from core.utils import *
|
||||
from core.websocket import WebSocket
|
||||
from core.utils.encoder import ComplexEncoder
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
|
@ -72,12 +75,14 @@ class CraftBeerPi():
|
|||
self.kettle = KettleController(self)
|
||||
self.step = StepController(self)
|
||||
self.notification = NotificationController(self)
|
||||
#self.dummy = MyComp(self)
|
||||
|
||||
|
||||
|
||||
|
||||
self.login = Login(self)
|
||||
|
||||
self.plugin.load_plugins()
|
||||
self.plugin.load_plugins_from_evn()
|
||||
self.register_events(self.ws)
|
||||
|
||||
|
||||
|
@ -193,7 +198,7 @@ class CraftBeerPi():
|
|||
|
||||
|
||||
if url_prefix is not None:
|
||||
print("Prefx", url_prefix)
|
||||
logger.debug("URL Prefix: %s " % (url_prefix,))
|
||||
sub = web.Application()
|
||||
sub.add_routes(routes)
|
||||
if static is not None:
|
||||
|
@ -242,12 +247,13 @@ class CraftBeerPi():
|
|||
:return:
|
||||
'''
|
||||
|
||||
print("INIT CONTROLLER")
|
||||
|
||||
|
||||
from pyfiglet import Figlet
|
||||
f = Figlet(font='big')
|
||||
print("")
|
||||
print(f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
|
||||
|
||||
print("")
|
||||
async def init_database(app):
|
||||
await DBModel.test_connection()
|
||||
|
||||
|
@ -256,14 +262,22 @@ class CraftBeerPi():
|
|||
await self.step.init()
|
||||
await self.actor.init()
|
||||
await self.kettle.init()
|
||||
await self.config2.init()
|
||||
|
||||
|
||||
print(self.sensor.info())
|
||||
|
||||
print(self.actor.info())
|
||||
import pprint
|
||||
pprint.pprint(self.bus.dump())
|
||||
#pprint.pprint(self.bus.dump())
|
||||
|
||||
|
||||
async def load_plugins(app):
|
||||
#await PluginController.load_plugin_list()
|
||||
#self.plugin.load_plugins()
|
||||
|
||||
|
||||
|
||||
pass
|
||||
|
||||
async def call_initializer(app):
|
||||
|
|
|
@ -36,13 +36,9 @@ class DBModel(object):
|
|||
@classmethod
|
||||
async def test_connection(self):
|
||||
|
||||
|
||||
async with aiosqlite.connect(TEST_DB) as db:
|
||||
|
||||
assert isinstance(db, aiosqlite.Connection)
|
||||
this_directory = os.path.dirname(__file__)
|
||||
|
||||
|
||||
qry = open(os.path.join(this_directory, '../sql/create_table_user.sql'), 'r').read()
|
||||
cursor = await db.executescript(qry)
|
||||
|
||||
|
@ -67,7 +63,8 @@ class DBModel(object):
|
|||
if cls.__as_array__ is True:
|
||||
result.append(cls(row))
|
||||
else:
|
||||
result[row.get("id")] = cls(row)
|
||||
|
||||
result[row.get(cls.__priamry_key__)] = cls(row)
|
||||
await cursor.close()
|
||||
|
||||
return result
|
||||
|
@ -121,7 +118,7 @@ class DBModel(object):
|
|||
else:
|
||||
data = data + (kwargs.get(f),)
|
||||
|
||||
print("INSERT DATA", query, data)
|
||||
|
||||
cursor = await db.execute(query, data)
|
||||
await db.commit()
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import asyncio
|
||||
import inspect
|
||||
import logging
|
||||
import json
|
||||
|
||||
import time
|
||||
|
||||
|
||||
class EventBus(object):
|
||||
|
@ -101,13 +98,13 @@ class EventBus(object):
|
|||
else:
|
||||
self.loop = asyncio.get_event_loop()
|
||||
|
||||
print(self.loop)
|
||||
|
||||
|
||||
def sync_fire(self,topic: str,timeout=1, **kwargs):
|
||||
self.loop.create_task(self.fire(topic=topic, timeout=timeout, **kwargs))
|
||||
|
||||
async def fire(self, topic: str, timeout=1, **kwargs):
|
||||
|
||||
print("FIRE")
|
||||
futures = {}
|
||||
|
||||
async def wait(futures):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from aiohttp import web
|
||||
|
||||
from core.api.decorator import on_event, request_mapping
|
||||
from core.api.extension import CBPiExtension
|
||||
from cbpi_api import *
|
||||
from core.controller.crud_controller import CRUDController
|
||||
from core.database.orm_framework import DBModel
|
||||
from core.http_endpoints.http_api import HttpAPI
|
||||
|
@ -32,12 +31,12 @@ class MyComp(CBPiExtension, CRUDController, HttpAPI):
|
|||
|
||||
@on_event(topic="actor/#")
|
||||
async def listen(self, **kwargs):
|
||||
print("Test", kwargs)
|
||||
pass
|
||||
|
||||
|
||||
@on_event(topic="kettle/+/automatic")
|
||||
async def listen2(self, **kwargs):
|
||||
print("HANDLE AUTOMATIC", kwargs)
|
||||
|
||||
|
||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % 1, id=1)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
|
||||
from core.api import CBPiActor, Property, action
|
||||
from cbpi_api import *
|
||||
|
||||
|
||||
class CustomActor(CBPiActor):
|
||||
|
@ -9,10 +9,10 @@ class CustomActor(CBPiActor):
|
|||
gpio = Property.Number(label="Test")
|
||||
|
||||
def init(self):
|
||||
print("#########INIT MY CUSTOM ACTOR")
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
print("#########STOP MY CUSTOM ACTOR")
|
||||
pass
|
||||
|
||||
|
||||
@action(key="name", parameters={})
|
||||
|
@ -23,14 +23,14 @@ class CustomActor(CBPiActor):
|
|||
super().state()
|
||||
|
||||
def off(self):
|
||||
print("OFF", self.gpio)
|
||||
|
||||
|
||||
# Code to swtich the actor off goes here
|
||||
|
||||
self.state = False
|
||||
|
||||
def on(self, power=100):
|
||||
print("ON", self.gpio)
|
||||
|
||||
|
||||
# Code to swtich the actor on goes here
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import asyncio
|
||||
|
||||
from core.api import Property, on_event
|
||||
from core.api.kettle_logic import CBPiKettleLogic
|
||||
|
||||
from cbpi_api import *
|
||||
|
||||
class CustomLogic(CBPiKettleLogic):
|
||||
|
||||
|
@ -29,14 +27,14 @@ class CustomLogic(CBPiKettleLogic):
|
|||
if timeout is not None:
|
||||
|
||||
try:
|
||||
print("----> WAIT FOR FUTURE")
|
||||
|
||||
await asyncio.wait_for(future_obj, timeout=timeout)
|
||||
print("------> TIMEOUT")
|
||||
|
||||
return future_obj.result()
|
||||
except asyncio.TimeoutError:
|
||||
print('timeout!')
|
||||
pass
|
||||
else:
|
||||
print("----> WAIT FOR FUTURE")
|
||||
|
||||
await future_obj
|
||||
return future_obj.result()
|
||||
|
||||
|
@ -51,10 +49,10 @@ class CustomLogic(CBPiKettleLogic):
|
|||
self.cbpi.bus.unregister(my_callback)
|
||||
kwargs["future"].set_result("AMAZING")
|
||||
else:
|
||||
print("OTHER VALUE", value)
|
||||
pass
|
||||
|
||||
result = await self.wait_for_event("sensor/1", callback=my_callback)
|
||||
print("THE RESULT", result)
|
||||
|
||||
|
||||
|
||||
'''
|
||||
|
@ -68,7 +66,7 @@ class CustomLogic(CBPiKettleLogic):
|
|||
break
|
||||
await asyncio.sleep(1)
|
||||
'''
|
||||
print("YES IM FINISHED STOP LOGIC")
|
||||
|
||||
|
||||
def setup(cbpi):
|
||||
|
||||
|
|
|
@ -2,9 +2,7 @@ import asyncio
|
|||
import logging
|
||||
import random
|
||||
|
||||
from core.api import CBPiActor, Property, action, background_task
|
||||
from core.api.sensor import CBPiSensor
|
||||
|
||||
from cbpi_api import *
|
||||
|
||||
class CustomSensor(CBPiSensor):
|
||||
|
||||
|
@ -38,7 +36,7 @@ class CustomSensor(CBPiSensor):
|
|||
|
||||
self.value = self.value + 1
|
||||
await cbpi.bus.fire("sensor/%s" % self.id, value=self.value)
|
||||
print("SENSOR IS RUNNING", self.value)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import asyncio
|
||||
|
||||
from core.api import Property, action
|
||||
from core.api.step import CBPiSimpleStep
|
||||
from cbpi_api import *
|
||||
|
||||
|
||||
class CustomStepCBPi(CBPiSimpleStep):
|
||||
|
@ -23,7 +22,7 @@ class CustomStepCBPi(CBPiSimpleStep):
|
|||
if self.i == 20:
|
||||
self.next()
|
||||
self.cbpi.notify(key="step", message="HELLO FROM STEP")
|
||||
print("RUN STEP", self.id, self.name, self.__dict__)
|
||||
|
||||
|
||||
|
||||
def setup(cbpi):
|
||||
|
|
|
@ -2,7 +2,9 @@ import logging
|
|||
|
||||
from aiohttp import web
|
||||
|
||||
from core.api.decorator import request_mapping
|
||||
|
||||
from cbpi_api import *
|
||||
|
||||
from core.utils.utils import json_dumps
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from aiohttp import web
|
||||
from aiohttp_auth import auth
|
||||
|
||||
from core.api.decorator import request_mapping
|
||||
from cbpi_api import *
|
||||
|
||||
|
||||
class Login():
|
||||
|
|
|
@ -86,7 +86,7 @@ class Scheduler(*bases):
|
|||
if self._closed:
|
||||
return
|
||||
self._closed = True # prevent adding new jobs
|
||||
print("####### CLOSE")
|
||||
|
||||
jobs = self._jobs
|
||||
if jobs:
|
||||
# cleanup pending queue
|
||||
|
@ -113,7 +113,7 @@ class Scheduler(*bases):
|
|||
|
||||
def _done(self, job):
|
||||
|
||||
print("JOB DONE")
|
||||
|
||||
self.cbpi.bus.sync_fire("job/%s/done" % job.type, type=job.type, key=job.name)
|
||||
self._jobs.discard(job)
|
||||
if not self.pending_count:
|
||||
|
|
|
@ -55,7 +55,7 @@ class MQTTMatcher(object):
|
|||
self._root = self.Node()
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
print("...",key, value)
|
||||
|
||||
node = self._root
|
||||
for sym in key.split('/'):
|
||||
|
||||
|
|
|
@ -7,15 +7,13 @@ class ComplexEncoder(JSONEncoder):
|
|||
|
||||
def default(self, obj):
|
||||
|
||||
from core.database.model import ActorModel
|
||||
from core.database.orm_framework import DBModel
|
||||
from core.api.kettle_logic import CBPiKettleLogic
|
||||
print("OBJECT", obj)
|
||||
|
||||
try:
|
||||
if isinstance(obj, DBModel):
|
||||
return obj.__dict__
|
||||
elif callable(getattr(obj, "reprJSON")):
|
||||
return obj.reprJSON()
|
||||
#elif callable(getattr(obj, "reprJSON")):
|
||||
# return obj.reprJSON()
|
||||
#elif isinstance(obj, ActorModel):
|
||||
# return None
|
||||
elif hasattr(obj, "callback"):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from pprint import pprint
|
||||
|
||||
|
||||
from core.api.property import Property
|
||||
from cbpi_api import *
|
||||
from core.utils.encoder import ComplexEncoder
|
||||
|
||||
__all__ = ['load_config',"json_dumps", "parse_props"]
|
||||
|
@ -16,10 +15,13 @@ from core.database.model import DBModel, ActorModel
|
|||
|
||||
def load_config(fname):
|
||||
try:
|
||||
|
||||
with open(fname, 'rt') as f:
|
||||
data = yaml.load(f)
|
||||
|
||||
return data
|
||||
except:
|
||||
except Exception as e:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -63,7 +65,7 @@ def parse_props(self, cls):
|
|||
key = method.__getattribute__("key")
|
||||
parameters = method.__getattribute__("parameters")
|
||||
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})
|
||||
pprint(result, width=200)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ import json
|
|||
import aiohttp
|
||||
from aiohttp import web
|
||||
from typing import Iterable, Callable
|
||||
|
||||
from core.api import on_event
|
||||
from cbpi_api import *
|
||||
|
||||
|
||||
class WebSocket:
|
||||
|
@ -19,11 +18,12 @@ class WebSocket:
|
|||
|
||||
@on_event(topic="#")
|
||||
async def listen(self, topic, **kwargs):
|
||||
print("WS", topic)
|
||||
|
||||
from core.utils.encoder import ComplexEncoder
|
||||
data = json.dumps(dict(topic=topic, data=dict(**kwargs)),skipkeys=True, check_circular=True, cls=ComplexEncoder)
|
||||
self.logger.info("PUSH %s " % data)
|
||||
|
||||
self.send(json.dumps(dict(topic=topic, data=dict(**kwargs)),skipkeys=True, check_circular=True, cls=ComplexEncoder))
|
||||
|
||||
self.send(data)
|
||||
|
||||
def send(self, data):
|
||||
|
||||
|
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
|
@ -21,7 +21,7 @@ ActorController
|
|||
CBPiActor
|
||||
^^^^^^^^^
|
||||
|
||||
.. autoclass:: core.api.actor.CBPiActor
|
||||
.. autoclass:: cbpi_api.CBPiActor
|
||||
:members:
|
||||
:private-members:
|
||||
:undoc-members:
|
||||
|
|
|
@ -16,7 +16,7 @@ CBPiKettleLogic
|
|||
^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
.. autoclass:: core.api.kettle_logic.CBPiKettleLogic
|
||||
.. autoclass:: cbpi_api.CBPiKettleLogic
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
|
|
@ -23,7 +23,7 @@ Custom Actor
|
|||
|
||||
|
||||
|
||||
.. autoclass:: core.api.property.Property
|
||||
.. autoclass:: cbpi_api.Property
|
||||
:members:
|
||||
:private-members:
|
||||
:undoc-members:
|
||||
|
|
|
@ -15,7 +15,7 @@ Sensor Controller
|
|||
CBPiSensor
|
||||
^^^^^^^^^^
|
||||
|
||||
.. autoclass:: core.api.sensor.CBPiSensor
|
||||
.. autoclass:: cbpi_api.CBPiSensor
|
||||
:members:
|
||||
:private-members:
|
||||
:undoc-members:
|
||||
|
|
|
@ -16,7 +16,7 @@ StepController
|
|||
CBPiSimpleStep
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. autoclass:: core.api.step.CBPiSimpleStep
|
||||
.. autoclass:: cbpi_api.CBPiSimpleStep
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
@ -30,7 +30,6 @@ This is an example of a custom step. The Step class need to extend Simple step.
|
|||
|
||||
.. literalinclude:: ../../core/extension/dummystep/__init__.py
|
||||
:caption: __init__.py
|
||||
:name: __init__-py
|
||||
:language: python
|
||||
:linenos:
|
||||
|
||||
|
|
2
run.py
2
run.py
|
@ -1,5 +1,3 @@
|
|||
from core.api.decorator import on_event
|
||||
from core.controller.notification_controller import NotificationController
|
||||
from core.craftbeerpi import CraftBeerPi
|
||||
|
||||
|
||||
|
|
0
sensor_None.log
Normal file
0
sensor_None.log
Normal file
56
tests/test_config.py
Normal file
56
tests/test_config.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
import asyncio
|
||||
import time
|
||||
|
||||
import aiosqlite
|
||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||
from core.craftbeerpi import CraftBeerPi
|
||||
from cbpi_api.config import ConfigType
|
||||
|
||||
class ConfigTestCase(AioHTTPTestCase):
|
||||
|
||||
|
||||
async def get_application(self):
|
||||
self.cbpi = CraftBeerPi()
|
||||
self.cbpi.setup()
|
||||
return self.cbpi.app
|
||||
|
||||
|
||||
@unittest_run_loop
|
||||
async def test_get(self):
|
||||
|
||||
assert await self.cbpi.config2.get("CBPI_TEST_1", 1) == "22"
|
||||
|
||||
@unittest_run_loop
|
||||
async def test_set_get(self):
|
||||
value = str(time.time())
|
||||
|
||||
await self.cbpi.config2.set("CBPI_TEST_2", value)
|
||||
|
||||
assert await self.cbpi.config2.get("CBPI_TEST_2", 1) == value
|
||||
|
||||
@unittest_run_loop
|
||||
async def test_add(self):
|
||||
value = str(time.time())
|
||||
key = "CBPI_TEST_3"
|
||||
async with aiosqlite.connect("./craftbeerpi.db") as db:
|
||||
await db.execute("DELETE FROM config WHERE name = ? ", (key,))
|
||||
await db.commit()
|
||||
|
||||
await self.cbpi.config2.add(key, value, type=ConfigType.STRING, description="test")
|
||||
|
||||
@unittest_run_loop
|
||||
async def test_http_set(self):
|
||||
value = str(time.time())
|
||||
key = "CBPI_TEST_3"
|
||||
await self.cbpi.config2.set(key, value)
|
||||
assert await self.cbpi.config2.get(key, 1) == value
|
||||
|
||||
resp = await self.client.request("POST", "/config/%s/" % key, json={'value': '1'})
|
||||
assert resp.status == 204
|
||||
assert await self.cbpi.config2.get(key, -1) == "1"
|
||||
|
||||
@unittest_run_loop
|
||||
async def test_http_get(self):
|
||||
resp = await self.client.request("GET", "/config/")
|
||||
assert resp.status == 200
|
||||
#print(await eresp.json())
|
Loading…
Reference in a new issue