mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-25 08:28:23 +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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="PYTHON_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<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="jdk" jdkName="Python 3.7.1 virtualenv at ~/cbp42" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="dataSourceStorageLocal">
|
<component name="dataSourceStorageLocal">
|
||||||
<data-source name="craftbeerpi.db" uuid="5067e7fe-480d-4433-bc40-f2d1c38362a2">
|
<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" />
|
<case-sensitivity plain-identifiers="mixed" quoted-identifiers="mixed" />
|
||||||
<secret-storage>master_key</secret-storage>
|
<secret-storage>master_key</secret-storage>
|
||||||
<auth-required>false</auth-required>
|
<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
|
username: cbpi
|
||||||
password: 123
|
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 asyncio import Future
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
from cbpi_api import *
|
||||||
from core.api.decorator import on_event, request_mapping
|
|
||||||
from core.controller.crud_controller import CRUDController
|
from core.controller.crud_controller import CRUDController
|
||||||
from core.database.model import ActorModel
|
from core.database.model import ActorModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from core.http_endpoints.http_api import HttpAPI
|
||||||
|
from utils.encoder import ComplexEncoder
|
||||||
|
|
||||||
|
|
||||||
class ActorHttp(HttpAPI):
|
class ActorHttp(HttpAPI):
|
||||||
|
@ -17,11 +19,11 @@ class ActorHttp(HttpAPI):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
id = int(request.match_info['id'])
|
id = int(request.match_info['id'])
|
||||||
result = await self.cbpi.bus.fire2(topic="actor/%s/switch/on" % id, id=id, power=99)
|
result = await self.cbpi.bus.fire(topic="actor/%s/switch/on" % id, id=id, power=99)
|
||||||
print(result.timeout)
|
|
||||||
|
|
||||||
for key, value in result.results.items():
|
for key, value in result.results.items():
|
||||||
print(key, value.result)
|
pass
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ class ActorHttp(HttpAPI):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
id = int(request.match_info['id'])
|
id = int(request.match_info['id'])
|
||||||
print("ID", id)
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % id, id=id)
|
await self.cbpi.bus.fire(topic="actor/%s/toggle" % id, id=id)
|
||||||
return web.Response(status=204)
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@ -57,11 +59,16 @@ class ActorController(ActorHttp, CRUDController):
|
||||||
super(ActorController, self).__init__(cbpi)
|
super(ActorController, self).__init__(cbpi)
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
self.state = False;
|
self.state = False;
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
self.cbpi.register(self, "/actor")
|
self.cbpi.register(self, "/actor")
|
||||||
self.types = {}
|
self.types = {}
|
||||||
self.actors = {}
|
self.actors = {}
|
||||||
|
|
||||||
|
def info(self):
|
||||||
|
|
||||||
|
return json.dumps(dict(name="ActorController", types=self.types), cls=ComplexEncoder)
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -104,8 +111,8 @@ class ActorController(ActorHttp, CRUDController):
|
||||||
|
|
||||||
id = int(id)
|
id = int(id)
|
||||||
if id in self.cache:
|
if id in self.cache:
|
||||||
print("POWER ON")
|
self.logger.debug("ON %s" % id)
|
||||||
actor = self.cache[id ].instance
|
actor = self.cache[id].instance
|
||||||
await self.cbpi.bus.fire("actor/%s/on/ok" % id)
|
await self.cbpi.bus.fire("actor/%s/on/ok" % id)
|
||||||
actor.on(power)
|
actor.on(power)
|
||||||
|
|
||||||
|
@ -122,6 +129,7 @@ class ActorController(ActorHttp, CRUDController):
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
self.logger.debug("TOGGLE %s" % id)
|
||||||
id = int(id)
|
id = int(id)
|
||||||
if id in self.cache:
|
if id in self.cache:
|
||||||
actor = self.cache[id].instance
|
actor = self.cache[id].instance
|
||||||
|
@ -141,6 +149,7 @@ class ActorController(ActorHttp, CRUDController):
|
||||||
:param kwargs:
|
:param kwargs:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.logger.debug("OFF %s" % id)
|
||||||
id = int(id)
|
id = int(id)
|
||||||
|
|
||||||
if id in self.cache:
|
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.controller.crud_controller import CRUDController
|
||||||
from core.database.model import ConfigModel
|
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
|
The main actor controller
|
||||||
|
@ -10,9 +38,35 @@ class ConfigController(CRUDController):
|
||||||
model = ConfigModel
|
model = ConfigModel
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
super(ConfigController, self).__init__(cbpi)
|
self.cache = {}
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
|
|
||||||
self.cbpi.register(self, "/config")
|
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
|
import pprint
|
||||||
from abc import abstractmethod,ABCMeta
|
from abc import ABCMeta
|
||||||
|
|
||||||
from core.utils.encoder import ComplexEncoder
|
|
||||||
|
|
||||||
|
|
||||||
class CRUDController(metaclass=ABCMeta):
|
class CRUDController(metaclass=ABCMeta):
|
||||||
|
@ -141,10 +138,10 @@ class CRUDController(metaclass=ABCMeta):
|
||||||
await self._post_delete_callback(id)
|
await self._post_delete_callback(id)
|
||||||
try:
|
try:
|
||||||
if self.caching is True:
|
if self.caching is True:
|
||||||
print("DELTE FROM ACHE")
|
|
||||||
del self.cache[int(id)]
|
del self.cache[int(id)]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
|
||||||
pass
|
pass
|
||||||
pprint.pprint(self.cache)
|
pprint.pprint(self.cache)
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/deleted" % id, id=id)
|
await self.cbpi.bus.fire(topic="actor/%s/deleted" % id, id=id)
|
||||||
|
|
|
@ -2,7 +2,8 @@ import re
|
||||||
|
|
||||||
from aiohttp import web
|
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.controller.crud_controller import CRUDController
|
||||||
from core.database.model import KettleModel
|
from core.database.model import KettleModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from core.http_endpoints.http_api import HttpAPI
|
||||||
|
@ -84,7 +85,7 @@ class KettleController(CRUDController):
|
||||||
kettle = self.cache[int(kid)]
|
kettle = self.cache[int(kid)]
|
||||||
kettle.instance = None
|
kettle.instance = None
|
||||||
|
|
||||||
print("STOP KETTLE LOGIC", kid)
|
|
||||||
|
|
||||||
@on_event(topic="kettle/+/automatic")
|
@on_event(topic="kettle/+/automatic")
|
||||||
async def handle_automtic_event(self, id, **kwargs):
|
async def handle_automtic_event(self, id, **kwargs):
|
||||||
|
@ -97,9 +98,9 @@ class KettleController(CRUDController):
|
||||||
:return: None
|
:return: None
|
||||||
'''
|
'''
|
||||||
id = int(id)
|
id = int(id)
|
||||||
print("WOOOHO", type(id), self.cache)
|
|
||||||
if id in self.cache:
|
if id in self.cache:
|
||||||
print("id", id)
|
|
||||||
kettle = self.cache[id]
|
kettle = self.cache[id]
|
||||||
|
|
||||||
if hasattr(kettle, "instance") is False:
|
if hasattr(kettle, "instance") is False:
|
||||||
|
@ -111,7 +112,7 @@ class KettleController(CRUDController):
|
||||||
cfg = kettle.config.copy()
|
cfg = kettle.config.copy()
|
||||||
cfg.update(dict(cbpi=self.cbpi))
|
cfg.update(dict(cbpi=self.cbpi))
|
||||||
kettle.instance = clazz(**cfg)
|
kettle.instance = clazz(**cfg)
|
||||||
print("START LOGIC")
|
|
||||||
await self.cbpi.start_job(kettle.instance.run(), "Kettle_logic_%s" % kettle.id, "kettle_logic%s"%id)
|
await self.cbpi.start_job(kettle.instance.run(), "Kettle_logic_%s" % kettle.id, "kettle_logic%s"%id)
|
||||||
else:
|
else:
|
||||||
kettle.instance.running = False
|
kettle.instance.running = False
|
||||||
|
@ -120,7 +121,7 @@ class KettleController(CRUDController):
|
||||||
|
|
||||||
def _is_logic_running(self, kettle_id):
|
def _is_logic_running(self, kettle_id):
|
||||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
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):
|
async def heater_on(self, id):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from core.api.decorator import on_event
|
from cbpi_api import *
|
||||||
|
|
||||||
|
|
||||||
class NotificationController():
|
class NotificationController():
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import imp
|
||||||
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
|
@ -7,17 +10,11 @@ import aiohttp
|
||||||
import yaml
|
import yaml
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from core.api.actor import CBPiActor
|
from cbpi_api import *
|
||||||
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 core.utils.utils import load_config, json_dumps
|
from core.utils.utils import load_config, json_dumps
|
||||||
|
|
||||||
logger = logging.getLogger(__file__)
|
logger = logging.getLogger(__name__)
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
class PluginController():
|
class PluginController():
|
||||||
|
|
||||||
|
@ -64,6 +61,18 @@ class PluginController():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(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)
|
@request_mapping(path="/plugins", method="GET", auth_required=False)
|
||||||
async def get_plugins(self, request):
|
async def get_plugins(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -90,7 +99,7 @@ class PluginController():
|
||||||
:param clazz: actor class
|
:param clazz: actor class
|
||||||
:return: None
|
:return: None
|
||||||
'''
|
'''
|
||||||
print("REGISTER", name, clazz)
|
|
||||||
if issubclass(clazz, CBPiActor):
|
if issubclass(clazz, CBPiActor):
|
||||||
self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
|
self.cbpi.actor.types[name] = {"class": clazz, "config": self._parse_props(clazz)}
|
||||||
|
|
||||||
|
@ -103,12 +112,12 @@ 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)
|
||||||
print(self.cbpi.step.types)
|
|
||||||
if issubclass(clazz, CBPiExtension):
|
if issubclass(clazz, CBPiExtension):
|
||||||
self.c = clazz(self.cbpi)
|
self.c = clazz(self.cbpi)
|
||||||
|
|
||||||
def _parse_props(self, cls):
|
def _parse_props(self, cls):
|
||||||
print("PARSE", cls)
|
|
||||||
name = cls.__name__
|
name = cls.__name__
|
||||||
|
|
||||||
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
result = {"name": name, "class": cls, "properties": [], "actions": []}
|
||||||
|
@ -143,5 +152,5 @@ class PluginController():
|
||||||
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})
|
||||||
pprint(result)
|
|
||||||
return result
|
return result
|
|
@ -1,10 +1,10 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from logging.handlers import TimedRotatingFileHandler
|
from logging.handlers import TimedRotatingFileHandler
|
||||||
|
from core.utils.encoder import ComplexEncoder
|
||||||
from core.job.aiohttp import get_scheduler_from_app
|
from core.job.aiohttp import get_scheduler_from_app
|
||||||
|
from cbpi_api import *
|
||||||
from core.api.decorator import background_task
|
|
||||||
from core.controller.crud_controller import CRUDController
|
from core.controller.crud_controller import CRUDController
|
||||||
from core.database.model import SensorModel
|
from core.database.model import SensorModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from core.http_endpoints.http_api import HttpAPI
|
||||||
|
@ -22,7 +22,9 @@ class SensorController(CRUDController, HttpAPI):
|
||||||
|
|
||||||
self.sensors = {}
|
self.sensors = {}
|
||||||
|
|
||||||
|
def info(self):
|
||||||
|
|
||||||
|
return json.dumps(dict(name="SensorController", types=self.types), cls=ComplexEncoder)
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
'''
|
'''
|
||||||
|
@ -31,9 +33,9 @@ class SensorController(CRUDController, HttpAPI):
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
await super(SensorController, self).init()
|
await super(SensorController, self).init()
|
||||||
print("INIT SENSOR")
|
|
||||||
for name, clazz in self.types.items():
|
for name, clazz in self.types.items():
|
||||||
print("Type", name)
|
pass
|
||||||
|
|
||||||
for id, value in self.cache.items():
|
for id, value in self.cache.items():
|
||||||
if value.type in self.types:
|
if value.type in self.types:
|
||||||
|
@ -43,7 +45,7 @@ class SensorController(CRUDController, HttpAPI):
|
||||||
self.cache[id].instance = clazz(**cfg)
|
self.cache[id].instance = clazz(**cfg)
|
||||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
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")
|
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):
|
async def get_value(self, id):
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from aiohttp import web
|
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.controller.crud_controller import CRUDController
|
||||||
from core.database.model import StepModel
|
from core.database.model import StepModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from core.http_endpoints.http_api import HttpAPI
|
||||||
|
@ -36,7 +36,7 @@ class StepController(HttpAPI, CRUDController):
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
await super(StepController, self).init()
|
await super(StepController, self).init()
|
||||||
print("INIT LAST STEP")
|
|
||||||
await self.init_after_startup()
|
await self.init_after_startup()
|
||||||
|
|
||||||
async def init_after_startup(self):
|
async def init_after_startup(self):
|
||||||
|
@ -45,14 +45,14 @@ class StepController(HttpAPI, CRUDController):
|
||||||
|
|
||||||
|
|
||||||
if step is not None:
|
if step is not None:
|
||||||
print("INIT LAST STEP", step.__dict__)
|
|
||||||
# get the type
|
# get the type
|
||||||
print(self.types)
|
|
||||||
step_type = self.types.get(step.type)
|
step_type = self.types.get(step.type)
|
||||||
|
|
||||||
if step_type is None:
|
if step_type is None:
|
||||||
# step type not found. cant restart step
|
# step type not found. cant restart step
|
||||||
print("STEP TYPE NONT FOUND")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if step.stepstate is not None:
|
if step.stepstate is not None:
|
||||||
|
@ -201,10 +201,10 @@ class StepController(HttpAPI, CRUDController):
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
print("IS SHUTODONW", self.cbpi.shutdown)
|
|
||||||
if self.cbpi.shutdown:
|
if self.cbpi.shutdown:
|
||||||
return
|
return
|
||||||
print("JOB DONE STEP")
|
|
||||||
self.cache[self.current_step.id].state = "D"
|
self.cache[self.current_step.id].state = "D"
|
||||||
step_id = self.current_step.id
|
step_id = self.current_step.id
|
||||||
self.current_step = None
|
self.current_step = None
|
||||||
|
@ -214,7 +214,7 @@ class StepController(HttpAPI, CRUDController):
|
||||||
|
|
||||||
|
|
||||||
def _get_manged_fields_as_array(self, type_cfg):
|
def _get_manged_fields_as_array(self, type_cfg):
|
||||||
print("tYPE", type_cfg)
|
|
||||||
result = []
|
result = []
|
||||||
for f in type_cfg.get("properties"):
|
for f in type_cfg.get("properties"):
|
||||||
result.append(f.get("name"))
|
result.append(f.get("name"))
|
||||||
|
@ -236,7 +236,7 @@ class StepController(HttpAPI, CRUDController):
|
||||||
inactive = await self.model.get_by_state("I")
|
inactive = await self.model.get_by_state("I")
|
||||||
active = await self.model.get_by_state("A")
|
active = await self.model.get_by_state("A")
|
||||||
|
|
||||||
print("STEPES", inactive, active)
|
|
||||||
|
|
||||||
if active is not None:
|
if active is not None:
|
||||||
active.state = 'D'
|
active.state = 'D'
|
||||||
|
|
|
@ -2,7 +2,7 @@ import datetime
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiojobs.aiohttp import get_scheduler_from_app
|
from aiojobs.aiohttp import get_scheduler_from_app
|
||||||
|
|
||||||
from core.api.decorator import request_mapping
|
from cbpi_api import *
|
||||||
|
|
||||||
|
|
||||||
class SystemController():
|
class SystemController():
|
||||||
|
@ -28,9 +28,7 @@ class SystemController():
|
||||||
result = []
|
result = []
|
||||||
for j in scheduler:
|
for j in scheduler:
|
||||||
try:
|
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))
|
result.append(dict(name=j.name, type=j.type, time=j.start_time))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -26,8 +26,11 @@ from core.eventbus import EventBus
|
||||||
from core.http_endpoints.http_login import Login
|
from core.http_endpoints.http_login import Login
|
||||||
from core.utils import *
|
from core.utils import *
|
||||||
from core.websocket import WebSocket
|
from core.websocket import WebSocket
|
||||||
|
from core.utils.encoder import ComplexEncoder
|
||||||
|
|
||||||
logger = logging.getLogger(__file__)
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,12 +75,14 @@ class CraftBeerPi():
|
||||||
self.kettle = KettleController(self)
|
self.kettle = KettleController(self)
|
||||||
self.step = StepController(self)
|
self.step = StepController(self)
|
||||||
self.notification = NotificationController(self)
|
self.notification = NotificationController(self)
|
||||||
#self.dummy = MyComp(self)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.login = Login(self)
|
self.login = Login(self)
|
||||||
|
|
||||||
self.plugin.load_plugins()
|
self.plugin.load_plugins()
|
||||||
|
self.plugin.load_plugins_from_evn()
|
||||||
self.register_events(self.ws)
|
self.register_events(self.ws)
|
||||||
|
|
||||||
|
|
||||||
|
@ -193,7 +198,7 @@ class CraftBeerPi():
|
||||||
|
|
||||||
|
|
||||||
if url_prefix is not None:
|
if url_prefix is not None:
|
||||||
print("Prefx", url_prefix)
|
logger.debug("URL Prefix: %s " % (url_prefix,))
|
||||||
sub = web.Application()
|
sub = web.Application()
|
||||||
sub.add_routes(routes)
|
sub.add_routes(routes)
|
||||||
if static is not None:
|
if static is not None:
|
||||||
|
@ -242,12 +247,13 @@ class CraftBeerPi():
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
print("INIT CONTROLLER")
|
|
||||||
|
|
||||||
from pyfiglet import Figlet
|
from pyfiglet import Figlet
|
||||||
f = Figlet(font='big')
|
f = Figlet(font='big')
|
||||||
|
print("")
|
||||||
print(f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
|
print(f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
|
||||||
|
print("")
|
||||||
async def init_database(app):
|
async def init_database(app):
|
||||||
await DBModel.test_connection()
|
await DBModel.test_connection()
|
||||||
|
|
||||||
|
@ -256,14 +262,22 @@ class CraftBeerPi():
|
||||||
await self.step.init()
|
await self.step.init()
|
||||||
await self.actor.init()
|
await self.actor.init()
|
||||||
await self.kettle.init()
|
await self.kettle.init()
|
||||||
|
await self.config2.init()
|
||||||
|
|
||||||
|
|
||||||
|
print(self.sensor.info())
|
||||||
|
|
||||||
|
print(self.actor.info())
|
||||||
import pprint
|
import pprint
|
||||||
pprint.pprint(self.bus.dump())
|
#pprint.pprint(self.bus.dump())
|
||||||
|
|
||||||
|
|
||||||
async def load_plugins(app):
|
async def load_plugins(app):
|
||||||
#await PluginController.load_plugin_list()
|
#await PluginController.load_plugin_list()
|
||||||
#self.plugin.load_plugins()
|
#self.plugin.load_plugins()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def call_initializer(app):
|
async def call_initializer(app):
|
||||||
|
|
|
@ -36,13 +36,9 @@ class DBModel(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
async def test_connection(self):
|
async def test_connection(self):
|
||||||
|
|
||||||
|
|
||||||
async with aiosqlite.connect(TEST_DB) as db:
|
async with aiosqlite.connect(TEST_DB) as db:
|
||||||
|
|
||||||
assert isinstance(db, aiosqlite.Connection)
|
assert isinstance(db, aiosqlite.Connection)
|
||||||
this_directory = os.path.dirname(__file__)
|
this_directory = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
qry = open(os.path.join(this_directory, '../sql/create_table_user.sql'), 'r').read()
|
qry = open(os.path.join(this_directory, '../sql/create_table_user.sql'), 'r').read()
|
||||||
cursor = await db.executescript(qry)
|
cursor = await db.executescript(qry)
|
||||||
|
|
||||||
|
@ -67,7 +63,8 @@ class DBModel(object):
|
||||||
if cls.__as_array__ is True:
|
if cls.__as_array__ is True:
|
||||||
result.append(cls(row))
|
result.append(cls(row))
|
||||||
else:
|
else:
|
||||||
result[row.get("id")] = cls(row)
|
|
||||||
|
result[row.get(cls.__priamry_key__)] = cls(row)
|
||||||
await cursor.close()
|
await cursor.close()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -121,7 +118,7 @@ class DBModel(object):
|
||||||
else:
|
else:
|
||||||
data = data + (kwargs.get(f),)
|
data = data + (kwargs.get(f),)
|
||||||
|
|
||||||
print("INSERT DATA", query, data)
|
|
||||||
cursor = await db.execute(query, data)
|
cursor = await db.execute(query, data)
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import json
|
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
class EventBus(object):
|
class EventBus(object):
|
||||||
|
@ -101,13 +98,13 @@ class EventBus(object):
|
||||||
else:
|
else:
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
print(self.loop)
|
|
||||||
|
|
||||||
def sync_fire(self,topic: str,timeout=1, **kwargs):
|
def sync_fire(self,topic: str,timeout=1, **kwargs):
|
||||||
self.loop.create_task(self.fire(topic=topic, timeout=timeout, **kwargs))
|
self.loop.create_task(self.fire(topic=topic, timeout=timeout, **kwargs))
|
||||||
|
|
||||||
async def fire(self, topic: str, timeout=1, **kwargs):
|
async def fire(self, topic: str, timeout=1, **kwargs):
|
||||||
|
print("FIRE")
|
||||||
futures = {}
|
futures = {}
|
||||||
|
|
||||||
async def wait(futures):
|
async def wait(futures):
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from core.api.decorator import on_event, request_mapping
|
from cbpi_api import *
|
||||||
from core.api.extension import CBPiExtension
|
|
||||||
from core.controller.crud_controller import CRUDController
|
from core.controller.crud_controller import CRUDController
|
||||||
from core.database.orm_framework import DBModel
|
from core.database.orm_framework import DBModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from core.http_endpoints.http_api import HttpAPI
|
||||||
|
@ -32,12 +31,12 @@ class MyComp(CBPiExtension, CRUDController, HttpAPI):
|
||||||
|
|
||||||
@on_event(topic="actor/#")
|
@on_event(topic="actor/#")
|
||||||
async def listen(self, **kwargs):
|
async def listen(self, **kwargs):
|
||||||
print("Test", kwargs)
|
pass
|
||||||
|
|
||||||
|
|
||||||
@on_event(topic="kettle/+/automatic")
|
@on_event(topic="kettle/+/automatic")
|
||||||
async def listen2(self, **kwargs):
|
async def listen2(self, **kwargs):
|
||||||
print("HANDLE AUTOMATIC", kwargs)
|
|
||||||
|
|
||||||
await self.cbpi.bus.fire(topic="actor/%s/toggle" % 1, id=1)
|
await self.cbpi.bus.fire(topic="actor/%s/toggle" % 1, id=1)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from core.api import CBPiActor, Property, action
|
from cbpi_api import *
|
||||||
|
|
||||||
|
|
||||||
class CustomActor(CBPiActor):
|
class CustomActor(CBPiActor):
|
||||||
|
@ -9,10 +9,10 @@ class CustomActor(CBPiActor):
|
||||||
gpio = Property.Number(label="Test")
|
gpio = Property.Number(label="Test")
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
print("#########INIT MY CUSTOM ACTOR")
|
pass
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
print("#########STOP MY CUSTOM ACTOR")
|
pass
|
||||||
|
|
||||||
|
|
||||||
@action(key="name", parameters={})
|
@action(key="name", parameters={})
|
||||||
|
@ -23,14 +23,14 @@ class CustomActor(CBPiActor):
|
||||||
super().state()
|
super().state()
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
print("OFF", self.gpio)
|
|
||||||
|
|
||||||
# Code to swtich the actor off goes here
|
# Code to swtich the actor off goes here
|
||||||
|
|
||||||
self.state = False
|
self.state = False
|
||||||
|
|
||||||
def on(self, power=100):
|
def on(self, power=100):
|
||||||
print("ON", self.gpio)
|
|
||||||
|
|
||||||
# Code to swtich the actor on goes here
|
# Code to swtich the actor on goes here
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from core.api import Property, on_event
|
from cbpi_api import *
|
||||||
from core.api.kettle_logic import CBPiKettleLogic
|
|
||||||
|
|
||||||
|
|
||||||
class CustomLogic(CBPiKettleLogic):
|
class CustomLogic(CBPiKettleLogic):
|
||||||
|
|
||||||
|
@ -29,14 +27,14 @@ class CustomLogic(CBPiKettleLogic):
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print("----> WAIT FOR FUTURE")
|
|
||||||
await asyncio.wait_for(future_obj, timeout=timeout)
|
await asyncio.wait_for(future_obj, timeout=timeout)
|
||||||
print("------> TIMEOUT")
|
|
||||||
return future_obj.result()
|
return future_obj.result()
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
print('timeout!')
|
pass
|
||||||
else:
|
else:
|
||||||
print("----> WAIT FOR FUTURE")
|
|
||||||
await future_obj
|
await future_obj
|
||||||
return future_obj.result()
|
return future_obj.result()
|
||||||
|
|
||||||
|
@ -51,10 +49,10 @@ class CustomLogic(CBPiKettleLogic):
|
||||||
self.cbpi.bus.unregister(my_callback)
|
self.cbpi.bus.unregister(my_callback)
|
||||||
kwargs["future"].set_result("AMAZING")
|
kwargs["future"].set_result("AMAZING")
|
||||||
else:
|
else:
|
||||||
print("OTHER VALUE", value)
|
pass
|
||||||
|
|
||||||
result = await self.wait_for_event("sensor/1", callback=my_callback)
|
result = await self.wait_for_event("sensor/1", callback=my_callback)
|
||||||
print("THE RESULT", result)
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -68,7 +66,7 @@ class CustomLogic(CBPiKettleLogic):
|
||||||
break
|
break
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
'''
|
'''
|
||||||
print("YES IM FINISHED STOP LOGIC")
|
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ import asyncio
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from core.api import CBPiActor, Property, action, background_task
|
from cbpi_api import *
|
||||||
from core.api.sensor import CBPiSensor
|
|
||||||
|
|
||||||
|
|
||||||
class CustomSensor(CBPiSensor):
|
class CustomSensor(CBPiSensor):
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ class CustomSensor(CBPiSensor):
|
||||||
|
|
||||||
self.value = self.value + 1
|
self.value = self.value + 1
|
||||||
await cbpi.bus.fire("sensor/%s" % self.id, value=self.value)
|
await cbpi.bus.fire("sensor/%s" % self.id, value=self.value)
|
||||||
print("SENSOR IS RUNNING", self.value)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from core.api import Property, action
|
from cbpi_api import *
|
||||||
from core.api.step import CBPiSimpleStep
|
|
||||||
|
|
||||||
|
|
||||||
class CustomStepCBPi(CBPiSimpleStep):
|
class CustomStepCBPi(CBPiSimpleStep):
|
||||||
|
@ -23,7 +22,7 @@ class CustomStepCBPi(CBPiSimpleStep):
|
||||||
if self.i == 20:
|
if self.i == 20:
|
||||||
self.next()
|
self.next()
|
||||||
self.cbpi.notify(key="step", message="HELLO FROM STEP")
|
self.cbpi.notify(key="step", message="HELLO FROM STEP")
|
||||||
print("RUN STEP", self.id, self.name, self.__dict__)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
|
|
|
@ -2,7 +2,9 @@ import logging
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from core.api.decorator import request_mapping
|
|
||||||
|
from cbpi_api import *
|
||||||
|
|
||||||
from core.utils.utils import json_dumps
|
from core.utils.utils import json_dumps
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_auth import auth
|
from aiohttp_auth import auth
|
||||||
|
|
||||||
from core.api.decorator import request_mapping
|
from cbpi_api import *
|
||||||
|
|
||||||
|
|
||||||
class Login():
|
class Login():
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Scheduler(*bases):
|
||||||
if self._closed:
|
if self._closed:
|
||||||
return
|
return
|
||||||
self._closed = True # prevent adding new jobs
|
self._closed = True # prevent adding new jobs
|
||||||
print("####### CLOSE")
|
|
||||||
jobs = self._jobs
|
jobs = self._jobs
|
||||||
if jobs:
|
if jobs:
|
||||||
# cleanup pending queue
|
# cleanup pending queue
|
||||||
|
@ -113,7 +113,7 @@ class Scheduler(*bases):
|
||||||
|
|
||||||
def _done(self, job):
|
def _done(self, job):
|
||||||
|
|
||||||
print("JOB DONE")
|
|
||||||
self.cbpi.bus.sync_fire("job/%s/done" % job.type, type=job.type, key=job.name)
|
self.cbpi.bus.sync_fire("job/%s/done" % job.type, type=job.type, key=job.name)
|
||||||
self._jobs.discard(job)
|
self._jobs.discard(job)
|
||||||
if not self.pending_count:
|
if not self.pending_count:
|
||||||
|
|
|
@ -55,7 +55,7 @@ class MQTTMatcher(object):
|
||||||
self._root = self.Node()
|
self._root = self.Node()
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
print("...",key, value)
|
|
||||||
node = self._root
|
node = self._root
|
||||||
for sym in key.split('/'):
|
for sym in key.split('/'):
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,13 @@ class ComplexEncoder(JSONEncoder):
|
||||||
|
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
|
|
||||||
from core.database.model import ActorModel
|
|
||||||
from core.database.orm_framework import DBModel
|
from core.database.orm_framework import DBModel
|
||||||
from core.api.kettle_logic import CBPiKettleLogic
|
|
||||||
print("OBJECT", obj)
|
|
||||||
try:
|
try:
|
||||||
if isinstance(obj, DBModel):
|
if isinstance(obj, DBModel):
|
||||||
return obj.__dict__
|
return obj.__dict__
|
||||||
elif callable(getattr(obj, "reprJSON")):
|
#elif callable(getattr(obj, "reprJSON")):
|
||||||
return obj.reprJSON()
|
# return obj.reprJSON()
|
||||||
#elif isinstance(obj, ActorModel):
|
#elif isinstance(obj, ActorModel):
|
||||||
# return None
|
# return None
|
||||||
elif hasattr(obj, "callback"):
|
elif hasattr(obj, "callback"):
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
|
from cbpi_api import *
|
||||||
from core.api.property import Property
|
|
||||||
from core.utils.encoder import ComplexEncoder
|
from core.utils.encoder import ComplexEncoder
|
||||||
|
|
||||||
__all__ = ['load_config',"json_dumps", "parse_props"]
|
__all__ = ['load_config',"json_dumps", "parse_props"]
|
||||||
|
@ -16,10 +15,13 @@ from core.database.model import DBModel, ActorModel
|
||||||
|
|
||||||
def load_config(fname):
|
def load_config(fname):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
with open(fname, 'rt') as f:
|
with open(fname, 'rt') as f:
|
||||||
data = yaml.load(f)
|
data = yaml.load(f)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
except:
|
except Exception as e:
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ def parse_props(self, cls):
|
||||||
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})
|
||||||
pprint(result, width=200)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@ import json
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from typing import Iterable, Callable
|
from typing import Iterable, Callable
|
||||||
|
from cbpi_api import *
|
||||||
from core.api import on_event
|
|
||||||
|
|
||||||
|
|
||||||
class WebSocket:
|
class WebSocket:
|
||||||
|
@ -19,11 +18,12 @@ class WebSocket:
|
||||||
|
|
||||||
@on_event(topic="#")
|
@on_event(topic="#")
|
||||||
async def listen(self, topic, **kwargs):
|
async def listen(self, topic, **kwargs):
|
||||||
print("WS", topic)
|
|
||||||
|
|
||||||
from core.utils.encoder import ComplexEncoder
|
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):
|
def send(self, data):
|
||||||
|
|
||||||
|
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
|
@ -21,7 +21,7 @@ ActorController
|
||||||
CBPiActor
|
CBPiActor
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
.. autoclass:: core.api.actor.CBPiActor
|
.. autoclass:: cbpi_api.CBPiActor
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
|
@ -16,7 +16,7 @@ CBPiKettleLogic
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: core.api.kettle_logic.CBPiKettleLogic
|
.. autoclass:: cbpi_api.CBPiKettleLogic
|
||||||
:members:
|
:members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
:inherited-members:
|
:inherited-members:
|
||||||
|
|
|
@ -23,7 +23,7 @@ Custom Actor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: core.api.property.Property
|
.. autoclass:: cbpi_api.Property
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
|
@ -15,7 +15,7 @@ Sensor Controller
|
||||||
CBPiSensor
|
CBPiSensor
|
||||||
^^^^^^^^^^
|
^^^^^^^^^^
|
||||||
|
|
||||||
.. autoclass:: core.api.sensor.CBPiSensor
|
.. autoclass:: cbpi_api.CBPiSensor
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
|
@ -16,7 +16,7 @@ StepController
|
||||||
CBPiSimpleStep
|
CBPiSimpleStep
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. autoclass:: core.api.step.CBPiSimpleStep
|
.. autoclass:: cbpi_api.CBPiSimpleStep
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
: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
|
.. literalinclude:: ../../core/extension/dummystep/__init__.py
|
||||||
:caption: __init__.py
|
:caption: __init__.py
|
||||||
:name: __init__-py
|
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
: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
|
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