mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-24 16:08:11 +01:00
setuptools added
This commit is contained in:
parent
00c7a465d7
commit
7ab75f0b01
104 changed files with 1446 additions and 1208 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,4 +1,7 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
docs_src/build/
|
docs_src/build/
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
.idea
|
||||||
|
*.log
|
||||||
|
cbpi.egg-info
|
|
@ -2,13 +2,14 @@
|
||||||
<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" />
|
<sourceFolder url="file://$MODULE_DIR$/cbpi" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/test_env2" />
|
||||||
</content>
|
</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>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
<option name="projectConfiguration" value="py.test" />
|
<option name="projectConfiguration" value="pytest" />
|
||||||
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -14,5 +14,23 @@
|
||||||
<auth-required>false</auth-required>
|
<auth-required>false</auth-required>
|
||||||
<introspection-schemas>*:@</introspection-schemas>
|
<introspection-schemas>*:@</introspection-schemas>
|
||||||
</data-source>
|
</data-source>
|
||||||
|
<data-source name="craftbeerpi [3]" uuid="633d3113-4e25-4945-a8ff-56edb8af9fa9">
|
||||||
|
<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" />
|
||||||
|
<auth-required>false</auth-required>
|
||||||
|
<introspection-schemas>*:@</introspection-schemas>
|
||||||
|
</data-source>
|
||||||
|
<data-source name="craftbeerpi [4]" uuid="6a479d72-eae8-4efb-a6f4-370f17be2a85">
|
||||||
|
<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" />
|
||||||
|
<auth-required>false</auth-required>
|
||||||
|
<introspection-schemas>*:@</introspection-schemas>
|
||||||
|
</data-source>
|
||||||
|
<data-source name="craftbeerpi [2]" uuid="e7e939c3-e1f6-46db-8ea3-75b5f26d7b73">
|
||||||
|
<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" />
|
||||||
|
<auth-required>false</auth-required>
|
||||||
|
<introspection-schemas>*:@</introspection-schemas>
|
||||||
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -27,5 +27,56 @@
|
||||||
</library>
|
</library>
|
||||||
</libraries>
|
</libraries>
|
||||||
</data-source>
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="craftbeerpi [3]" uuid="633d3113-4e25-4945-a8ff-56edb8af9fa9">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/test/craftbeerpi.db</jdbc-url>
|
||||||
|
<driver-properties>
|
||||||
|
<property name="enable_load_extension" value="true" />
|
||||||
|
</driver-properties>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/xerial-sqlite-license.txt</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/sqlite-jdbc-3.16.1.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="craftbeerpi [4]" uuid="6a479d72-eae8-4efb-a6f4-370f17be2a85">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/test22/craftbeerpi.db</jdbc-url>
|
||||||
|
<driver-properties>
|
||||||
|
<property name="enable_load_extension" value="true" />
|
||||||
|
</driver-properties>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/xerial-sqlite-license.txt</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/sqlite-jdbc-3.16.1.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
<data-source source="LOCAL" name="craftbeerpi [2]" uuid="e7e939c3-e1f6-46db-8ea3-75b5f26d7b73">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/cbpi/craftbeerpi.db</jdbc-url>
|
||||||
|
<driver-properties>
|
||||||
|
<property name="enable_load_extension" value="true" />
|
||||||
|
</driver-properties>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/xerial-sqlite-license.txt</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/sqlite-jdbc-3.16.1.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
1125
.idea/workspace.xml
1125
.idea/workspace.xml
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,14 @@
|
||||||
FROM python:3
|
FROM python:3.5.6-stretch
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
COPY requirements.txt ./
|
COPY dist/cbpi-0.0.1.tar.gz ./
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install cbpi-0.0.1.tar.gz --no-cache-dir
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
CMD [ "python", "./run.py" ]
|
CMD [ "cbpi" ]
|
||||||
|
|
||||||
|
|
||||||
|
|
2
MANIFEST.in
Normal file
2
MANIFEST.in
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
recursive-include cbpi/config *
|
||||||
|
recursive-include cbpi/extension *
|
27
cbpi/api/__init__.py
Normal file
27
cbpi/api/__init__.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
__all__ = ["CBPiActor",
|
||||||
|
"CBPiExtension",
|
||||||
|
"Property",
|
||||||
|
"PropertyType",
|
||||||
|
"on_websocket_message",
|
||||||
|
"on_mqtt_message",
|
||||||
|
"on_event",
|
||||||
|
"on_startup",
|
||||||
|
"request_mapping",
|
||||||
|
"action",
|
||||||
|
"background_task",
|
||||||
|
"CBPiKettleLogic",
|
||||||
|
"CBPiSimpleStep",
|
||||||
|
"CBPiException",
|
||||||
|
"KettleException",
|
||||||
|
"SensorException",
|
||||||
|
"ActorException",
|
||||||
|
"CBPiSensor"]
|
||||||
|
|
||||||
|
from cbpi.api.actor import *
|
||||||
|
from cbpi.api.sensor import *
|
||||||
|
from cbpi.api.extension import *
|
||||||
|
from cbpi.api.property import *
|
||||||
|
from cbpi.api.decorator import *
|
||||||
|
from cbpi.api.kettle_logic import *
|
||||||
|
from cbpi.api.step import *
|
||||||
|
from cbpi.api.exceptions import *
|
49
cbpi/api/actor.py
Normal file
49
cbpi/api/actor.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
from abc import ABCMeta
|
||||||
|
|
||||||
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
|
||||||
|
__all__ = ["CBPiActor"]
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
8
cbpi/api/config.py
Normal file
8
cbpi/api/config.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
class ConfigType(Enum):
|
||||||
|
STRING = "string"
|
||||||
|
NUMBER = "number"
|
||||||
|
SELECT = "select"
|
||||||
|
|
||||||
|
|
96
cbpi/api/decorator.py
Normal file
96
cbpi/api/decorator.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
__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
|
14
cbpi/api/exceptions.py
Normal file
14
cbpi/api/exceptions.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
__all__ = ["CBPiException","KettleException","SensorException","ActorException"]
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class KettleException(CBPiException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SensorException(CBPiException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ActorException(CBPiException):
|
||||||
|
pass
|
54
cbpi/api/extension.py
Normal file
54
cbpi/api/extension.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
__all__ = ["CBPiExtension"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiExtension():
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwds):
|
||||||
|
|
||||||
|
for a in kwds:
|
||||||
|
logger.debug("Parameter: %s Value: %s" % ( a, kwds.get(a)))
|
||||||
|
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):
|
||||||
|
|
||||||
|
path = os.path.dirname(sys.modules[self.__class__.__module__].__file__)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("%s/config.yaml" % path, 'rt') as f:
|
||||||
|
data = yaml.load(f)
|
||||||
|
|
||||||
|
return data
|
||||||
|
except:
|
||||||
|
logger.warning("Faild to load config %s/config.yaml" % path)
|
||||||
|
|
||||||
|
|
||||||
|
|
38
cbpi/api/kettle_logic.py
Normal file
38
cbpi/api/kettle_logic.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from cbpi.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
|
113
cbpi/api/property.py
Normal file
113
cbpi/api/property.py
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
__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
|
38
cbpi/api/sensor.py
Normal file
38
cbpi/api/sensor.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from time import localtime, strftime
|
||||||
|
|
||||||
|
from cbpi.api.extension import CBPiExtension
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiSensor(CBPiExtension):
|
||||||
|
def __init__(self, *args, **kwds):
|
||||||
|
CBPiExtension.__init__(self, *args, **kwds)
|
||||||
|
self.logger = logging.getLogger(__file__)
|
||||||
|
self.data_logger = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def log_data(self, value):
|
||||||
|
|
||||||
|
formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime())
|
||||||
|
|
||||||
|
self.data_logger.debug("%s,%s" % (formatted_time, value))
|
||||||
|
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
|
||||||
|
|
||||||
|
self.data_logger = logging.getLogger('cbpi.sensor.%s' % self.id)
|
||||||
|
self.data_logger.propagate = False
|
||||||
|
self.data_logger.setLevel(logging.DEBUG)
|
||||||
|
handler = RotatingFileHandler('./logs/sensors/sensor_%s.log' % self.id, maxBytes=2000, backupCount=10)
|
||||||
|
self.data_logger.addHandler(handler)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def run(self, cbpi):
|
||||||
|
self.logger.warning("Sensor Init not implemented")
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
pass
|
134
cbpi/api/step.py
Normal file
134
cbpi/api/step.py
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import time
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from abc import abstractmethod,ABCMeta
|
||||||
|
|
||||||
|
|
||||||
|
class CBPiSimpleStep(metaclass=ABCMeta):
|
||||||
|
|
||||||
|
__dirty = False
|
||||||
|
managed_fields = []
|
||||||
|
_interval = 0.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()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
42
cbpi/cli.py
Normal file
42
cbpi/cli.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO,filename='./logs/app.log', filemode='a', format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
|
||||||
|
|
||||||
|
def create_plugin_file():
|
||||||
|
import os.path
|
||||||
|
if os.path.exists(os.path.join(".", 'config', "plugin_list.txt")) is False:
|
||||||
|
srcfile = os.path.join(os.path.dirname(__file__), "config", "plugin_list.txt")
|
||||||
|
destfile = os.path.join(".", 'config')
|
||||||
|
shutil.copy(srcfile, destfile)
|
||||||
|
|
||||||
|
def create_config_file():
|
||||||
|
import os.path
|
||||||
|
if os.path.exists(os.path.join(".", 'config', "config.yaml")) is False:
|
||||||
|
srcfile = os.path.join(os.path.dirname(__file__), "config", "config.yaml")
|
||||||
|
destfile = os.path.join(".", 'config')
|
||||||
|
shutil.copy(srcfile, destfile)
|
||||||
|
|
||||||
|
def create_home_folder_structure():
|
||||||
|
pathlib.Path(os.path.join(".", 'logs/sensors')).mkdir(parents=True, exist_ok=True)
|
||||||
|
pathlib.Path(os.path.join(".", 'config')).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
#import sys
|
||||||
|
#arg1, arg2 = sys.argv[1], sys.argv[2]
|
||||||
|
|
||||||
|
create_home_folder_structure()
|
||||||
|
create_plugin_file()
|
||||||
|
create_config_file()
|
||||||
|
|
||||||
|
|
||||||
|
cbpi = CraftBeerPi()
|
||||||
|
cbpi.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
11
cbpi/config/config.yaml
Normal file
11
cbpi/config/config.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
name: CraftBeerPi
|
||||||
|
version: 4.1
|
||||||
|
|
||||||
|
#index_url: /myext
|
||||||
|
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
username: cbpi
|
||||||
|
password: 123
|
||||||
|
|
1
cbpi/config/plugin_list.txt
Normal file
1
cbpi/config/plugin_list.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cbpi-actor
|
|
@ -1,11 +1,11 @@
|
||||||
import logging
|
import logging
|
||||||
from asyncio import Future
|
from asyncio import Future
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
from voluptuous import Schema
|
from voluptuous import Schema
|
||||||
|
|
||||||
from core.controller.crud_controller import CRUDController
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from core.database.model import ActorModel
|
from cbpi.database.model import ActorModel
|
||||||
|
|
||||||
|
|
||||||
class ActorController(CRUDController):
|
class ActorController(CRUDController):
|
|
@ -1,10 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from cbpi_api.config import ConfigType
|
from cbpi.api.config import ConfigType
|
||||||
|
from cbpi.database.model import ConfigModel
|
||||||
from core.database.model import ConfigModel
|
from cbpi.utils import load_config
|
||||||
from utils import load_config
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigController():
|
class ConfigController():
|
||||||
|
@ -21,7 +20,8 @@ class ConfigController():
|
||||||
|
|
||||||
async def init(self):
|
async def init(self):
|
||||||
this_directory = os.path.dirname(__file__)
|
this_directory = os.path.dirname(__file__)
|
||||||
self.static = load_config(os.path.join(this_directory, '../../config/config.yaml'))
|
|
||||||
|
self.static = load_config("./config/config.yaml")
|
||||||
items = await self.model.get_all()
|
items = await self.model.get_all()
|
||||||
for key, value in items.items():
|
for key, value in items.items():
|
||||||
self.cache[value.name] = value
|
self.cache[value.name] = value
|
|
@ -1,7 +1,7 @@
|
||||||
import pprint
|
import pprint
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
|
|
||||||
from cbpi_api.exceptions import CBPiException
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class CRUDController(metaclass=ABCMeta):
|
class CRUDController(metaclass=ABCMeta):
|
|
@ -2,8 +2,8 @@ import logging
|
||||||
|
|
||||||
from voluptuous import Schema, MultipleInvalid
|
from voluptuous import Schema, MultipleInvalid
|
||||||
|
|
||||||
from core.controller.crud_controller import CRUDController
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from core.database.model import DashboardModel, DashboardContentModel
|
from cbpi.database.model import DashboardModel, DashboardContentModel
|
||||||
|
|
||||||
|
|
||||||
class DashboardController(CRUDController):
|
class DashboardController(CRUDController):
|
|
@ -1,7 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from job.aiohttp import setup, get_scheduler_from_app
|
from cbpi.job.aiohttp import setup, get_scheduler_from_app
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
class JobController(object):
|
class JobController(object):
|
|
@ -1,13 +1,8 @@
|
||||||
import re
|
import re
|
||||||
|
from cbpi.api import *
|
||||||
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from cbpi_api import *
|
from cbpi.database.model import KettleModel
|
||||||
from cbpi_api.exceptions import KettleException, ActorException, SensorException
|
from cbpi.job.aiohttp import get_scheduler_from_app
|
||||||
|
|
||||||
from core.controller.crud_controller import CRUDController
|
|
||||||
from core.database.model import KettleModel
|
|
||||||
|
|
||||||
from core.job.aiohttp import get_scheduler_from_app
|
|
||||||
|
|
||||||
|
|
||||||
class KettleController(CRUDController):
|
class KettleController(CRUDController):
|
|
@ -1,4 +1,4 @@
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class NotificationController(object):
|
class NotificationController(object):
|
|
@ -5,9 +5,9 @@ from importlib import import_module
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import yaml
|
import yaml
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
from core.utils.utils import load_config, json_dumps
|
from cbpi.utils.utils import load_config, json_dumps
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -33,17 +33,20 @@ class PluginController():
|
||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
|
|
||||||
for filename in os.listdir("./core/extension"):
|
this_directory = os.path.dirname(__file__)
|
||||||
|
|
||||||
if os.path.isdir("./core/extension/" + filename) is False or filename == "__pycache__":
|
for filename in os.listdir(os.path.join(this_directory, "../extension")):
|
||||||
|
|
||||||
|
if os.path.isdir(os.path.join(this_directory, "../extension/") + filename) is False or filename == "__pycache__":
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
logger.info("Trying to load plugin %s" % filename)
|
logger.info("Trying to load plugin %s" % filename)
|
||||||
data = load_config("./core/extension/%s/config.yaml" % filename)
|
|
||||||
|
data = load_config(os.path.join(this_directory, "../extension/%s/config.yaml" % filename))
|
||||||
|
|
||||||
if(data.get("version") == 4):
|
if(data.get("version") == 4):
|
||||||
|
|
||||||
self.modules[filename] = import_module("core.extension.%s" % (filename))
|
self.modules[filename] = import_module("cbpi.extension.%s" % (filename))
|
||||||
self.modules[filename].setup(self.cbpi)
|
self.modules[filename].setup(self.cbpi)
|
||||||
|
|
||||||
logger.info("Plugin %s loaded successful" % filename)
|
logger.info("Plugin %s loaded successful" % filename)
|
||||||
|
@ -57,8 +60,8 @@ class PluginController():
|
||||||
def load_plugins_from_evn(self):
|
def load_plugins_from_evn(self):
|
||||||
|
|
||||||
plugins = []
|
plugins = []
|
||||||
|
this_directory = os.path.dirname(__file__)
|
||||||
with open('./config/plugin_list.txt') as f:
|
with open(os.path.join(this_directory, "../config/plugin_list.txt")) as f:
|
||||||
plugins = f.read().splitlines()
|
plugins = f.read().splitlines()
|
||||||
plugins = list(set(plugins))
|
plugins = list(set(plugins))
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
|
from cbpi.database.model import SensorModel
|
||||||
|
from cbpi.job.aiohttp import get_scheduler_from_app
|
||||||
|
|
||||||
from cbpi_api import request_mapping
|
|
||||||
|
|
||||||
from core.controller.crud_controller import CRUDController
|
|
||||||
from core.database.model import SensorModel
|
|
||||||
from core.job.aiohttp import get_scheduler_from_app
|
|
||||||
from core.utils.encoder import ComplexEncoder
|
|
||||||
|
|
||||||
|
|
||||||
class SensorController(CRUDController):
|
class SensorController(CRUDController):
|
|
@ -1,11 +1,9 @@
|
||||||
import asyncio
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from core.controller.crud_controller import CRUDController
|
from cbpi.database.model import StepModel
|
||||||
from core.database.model import StepModel
|
|
||||||
|
|
||||||
|
|
||||||
class StepController(CRUDController):
|
class StepController(CRUDController):
|
|
@ -2,9 +2,9 @@ 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 cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
from utils import json_dumps
|
from cbpi.utils import json_dumps
|
||||||
|
|
||||||
|
|
||||||
class SystemController():
|
class SystemController():
|
|
@ -1,5 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
from os import urandom
|
from os import urandom
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -7,33 +6,36 @@ from aiohttp_auth import auth
|
||||||
from aiohttp_session import session_middleware
|
from aiohttp_session import session_middleware
|
||||||
from aiohttp_session.cookie_storage import EncryptedCookieStorage
|
from aiohttp_session.cookie_storage import EncryptedCookieStorage
|
||||||
from aiohttp_swagger import setup_swagger
|
from aiohttp_swagger import setup_swagger
|
||||||
from cbpi_api.exceptions import CBPiException
|
from cbpi.api.exceptions import CBPiException
|
||||||
from voluptuous import MultipleInvalid
|
from voluptuous import MultipleInvalid
|
||||||
|
|
||||||
from controller.dashboard_controller import DashboardController
|
from cbpi.controller.dashboard_controller import DashboardController
|
||||||
from controller.job_controller import JobController
|
from cbpi.controller.job_controller import JobController
|
||||||
from core.controller.actor_controller import ActorController
|
from cbpi.controller.actor_controller import ActorController
|
||||||
from core.controller.config_controller import ConfigController
|
from cbpi.controller.config_controller import ConfigController
|
||||||
from core.controller.kettle_controller import KettleController
|
from cbpi.controller.kettle_controller import KettleController
|
||||||
from core.controller.notification_controller import NotificationController
|
from cbpi.controller.notification_controller import NotificationController
|
||||||
from core.controller.plugin_controller import PluginController
|
from cbpi.controller.plugin_controller import PluginController
|
||||||
from core.controller.sensor_controller import SensorController
|
from cbpi.controller.sensor_controller import SensorController
|
||||||
from core.controller.step_controller import StepController
|
from cbpi.controller.step_controller import StepController
|
||||||
from core.controller.system_controller import SystemController
|
from cbpi.controller.system_controller import SystemController
|
||||||
from core.database.model import DBModel
|
from cbpi.database.model import DBModel
|
||||||
from core.eventbus import CBPiEventBus
|
from cbpi.eventbus import CBPiEventBus
|
||||||
from core.http_endpoints.http_login import Login
|
from cbpi.http_endpoints.http_login import Login
|
||||||
from core.utils import *
|
from cbpi.utils import *
|
||||||
from core.websocket import CBPiWebSocket
|
from cbpi.websocket import CBPiWebSocket
|
||||||
from http_endpoints.http_actor import ActorHttpEndpoints
|
from cbpi.http_endpoints.http_actor import ActorHttpEndpoints
|
||||||
from http_endpoints.http_config import ConfigHttpEndpoints
|
from cbpi.http_endpoints.http_config import ConfigHttpEndpoints
|
||||||
from http_endpoints.http_dashboard import DashBoardHttpEndpoints
|
from cbpi.http_endpoints.http_dashboard import DashBoardHttpEndpoints
|
||||||
from http_endpoints.http_kettle import KettleHttpEndpoints
|
from cbpi.http_endpoints.http_kettle import KettleHttpEndpoints
|
||||||
from http_endpoints.http_sensor import SensorHttpEndpoints
|
from cbpi.http_endpoints.http_sensor import SensorHttpEndpoints
|
||||||
from http_endpoints.http_step import StepHttpEndpoints
|
from cbpi.http_endpoints.http_step import StepHttpEndpoints
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@web.middleware
|
@web.middleware
|
||||||
async def error_middleware(request, handler):
|
async def error_middleware(request, handler):
|
||||||
|
@ -56,7 +58,9 @@ async def error_middleware(request, handler):
|
||||||
class CraftBeerPi():
|
class CraftBeerPi():
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.static_config = load_config(os.path.join(os.path.dirname(__file__), '../config/config.yaml'))
|
|
||||||
|
|
||||||
|
self.static_config = load_config("./config/config.yaml")
|
||||||
self.database_file = "./craftbeerpi.db"
|
self.database_file = "./craftbeerpi.db"
|
||||||
logger.info("Init CraftBeerPI")
|
logger.info("Init CraftBeerPI")
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
from voluptuous import Schema, MultipleInvalid
|
|
||||||
|
|
||||||
from core.database.orm_framework import DBModel
|
|
||||||
|
from cbpi.database.orm_framework import DBModel
|
||||||
|
|
||||||
DATABASE_FILE = "./craftbeerpi.db"
|
DATABASE_FILE = "./craftbeerpi.db"
|
||||||
|
|
|
@ -2,7 +2,7 @@ import json
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from cbpi_api.exceptions import CBPiException
|
from cbpi.api import *
|
||||||
from voluptuous import MultipleInvalid, Schema
|
from voluptuous import MultipleInvalid, Schema
|
||||||
|
|
||||||
DATABASE_FILE = "./craftbeerpi.db"
|
DATABASE_FILE = "./craftbeerpi.db"
|
||||||
|
@ -38,7 +38,7 @@ class DBModel(object):
|
||||||
async with aiosqlite.connect(DATABASE_FILE) as db:
|
async with aiosqlite.connect(DATABASE_FILE) 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, '../../config/create_database.sql'), 'r').read()
|
qry = open(os.path.join(this_directory, "../config/create_database.sql"), 'r').read()
|
||||||
cursor = await db.executescript(qry)
|
cursor = await db.executescript(qry)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
|
@ -2,10 +2,12 @@ import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from cbpi_api.exceptions import CBPiException
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class CBPiEventBus(object):
|
class CBPiEventBus(object):
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
class Node(object):
|
||||||
__slots__ = '_children', '_content'
|
__slots__ = '_children', '_content'
|
||||||
|
|
||||||
|
@ -22,17 +24,18 @@ class CBPiEventBus(object):
|
||||||
self.topic = topic
|
self.topic = topic
|
||||||
self.supports_future = supports_future
|
self.supports_future = supports_future
|
||||||
|
|
||||||
class Result():
|
class Result:
|
||||||
|
|
||||||
def __init__(self, result, timeout):
|
def __init__(self, result, timeout):
|
||||||
self.result = result
|
self.result = result
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|
||||||
class ResultContainer():
|
class ResultContainer:
|
||||||
|
|
||||||
def __init__(self, results, timeout=False):
|
def __init__(self, results, timeout=False):
|
||||||
self.results = {}
|
self.results = {}
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self._jobs = set()
|
||||||
for key, value in results.items():
|
for key, value in results.items():
|
||||||
if value.done() is True:
|
if value.done() is True:
|
||||||
self.results[key] = CBPiEventBus.Result(value.result(), True)
|
self.results[key] = CBPiEventBus.Result(value.result(), True)
|
||||||
|
@ -108,7 +111,7 @@ class CBPiEventBus(object):
|
||||||
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=0.5, **kwargs):
|
||||||
|
|
||||||
futures = {}
|
futures = {}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import os
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
from core.controller.crud_controller import CRUDController
|
from cbpi.controller.crud_controller import CRUDController
|
||||||
from core.database.orm_framework import DBModel
|
from cbpi.database.orm_framework import DBModel
|
||||||
from core.http_endpoints.http_api import HttpAPI
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
|
|
||||||
|
|
||||||
class DummyModel(DBModel):
|
class DummyModel(DBModel):
|
||||||
|
@ -14,7 +16,7 @@ class DummyModel(DBModel):
|
||||||
__table_name__ = "dummy"
|
__table_name__ = "dummy"
|
||||||
|
|
||||||
|
|
||||||
class MyComp(CBPiExtension, CRUDController, HttpAPI):
|
class MyComp(CBPiExtension, CRUDController, HttpCrudEndpoints):
|
||||||
model = DummyModel
|
model = DummyModel
|
||||||
|
|
||||||
def __init__(self, cbpi):
|
def __init__(self, cbpi):
|
||||||
|
@ -23,10 +25,12 @@ class MyComp(CBPiExtension, CRUDController, HttpAPI):
|
||||||
|
|
||||||
:param cbpi:
|
:param cbpi:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
self.cbpi = cbpi
|
self.cbpi = cbpi
|
||||||
# register component for http, events
|
# register component for http, events
|
||||||
# In addtion the sub folder static is exposed to access static content via http
|
# In addtion the sub folder static is exposed to access static content via http
|
||||||
self.cbpi.register(self, "/dummy", static="./core/extension/comp/static")
|
self.cbpi.register(self, "/dummy", static=os.path.join(os.path.dirname(__file__), "static"))
|
||||||
|
|
||||||
|
|
||||||
@on_event(topic="actor/#")
|
@on_event(topic="actor/#")
|
|
@ -1,8 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
class CustomLogic(CBPiKettleLogic):
|
class CustomLogic(CBPiKettleLogic):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import asyncio
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
class CustomSensor(CBPiSensor):
|
class CustomSensor(CBPiSensor):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class CustomStepCBPi(CBPiSimpleStep):
|
class CustomStepCBPi(CBPiSimpleStep):
|
|
@ -1,8 +1,8 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import request_mapping
|
from cbpi.api import *
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
|
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
auth = False
|
auth = False
|
||||||
|
|
||||||
class ActorHttpEndpoints(HttpCrudEndpoints):
|
class ActorHttpEndpoints(HttpCrudEndpoints):
|
|
@ -1,9 +1,8 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import request_mapping
|
from cbpi.api import *
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
|
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
from cbpi.utils import json_dumps
|
||||||
from utils import json_dumps
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
|
|
||||||
|
|
||||||
class ConfigHttpEndpoints(HttpCrudEndpoints):
|
class ConfigHttpEndpoints(HttpCrudEndpoints):
|
|
@ -1,9 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
from core.utils.utils import json_dumps
|
from cbpi.utils.utils import json_dumps
|
||||||
|
|
||||||
|
|
||||||
class HttpCrudEndpoints():
|
class HttpCrudEndpoints():
|
|
@ -1,10 +1,9 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import request_mapping
|
from cbpi.api import *
|
||||||
from voluptuous import Schema
|
from voluptuous import Schema
|
||||||
|
|
||||||
from database.model import DashboardContentModel
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
from cbpi.utils import json_dumps
|
||||||
from utils import json_dumps
|
|
||||||
|
|
||||||
|
|
||||||
class DashBoardHttpEndpoints(HttpCrudEndpoints):
|
class DashBoardHttpEndpoints(HttpCrudEndpoints):
|
|
@ -1,8 +1,8 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import request_mapping
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
auth = False
|
auth = False
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_auth import auth
|
from aiohttp_auth import auth
|
||||||
|
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
|
|
||||||
|
|
||||||
class Login():
|
class Login():
|
|
@ -1,8 +1,6 @@
|
||||||
from aiohttp import web
|
from cbpi.api import request_mapping
|
||||||
from cbpi_api import request_mapping
|
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
|
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
|
|
||||||
|
|
||||||
class SensorHttpEndpoints(HttpCrudEndpoints):
|
class SensorHttpEndpoints(HttpCrudEndpoints):
|
|
@ -1,8 +1,8 @@
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import request_mapping
|
from cbpi.api import *
|
||||||
from cbpi_api.exceptions import CBPiException
|
|
||||||
|
|
||||||
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
|
||||||
|
from cbpi.http_endpoints.http_curd_endpoints import HttpCrudEndpoints
|
||||||
|
|
||||||
|
|
||||||
class StepHttpEndpoints(HttpCrudEndpoints):
|
class StepHttpEndpoints(HttpCrudEndpoints):
|
|
@ -1,5 +1,5 @@
|
||||||
from aiojobs.aiohttp import get_scheduler_from_app
|
from aiojobs.aiohttp import get_scheduler_from_app
|
||||||
from core.mqtt_matcher import MQTTMatcher
|
from cbpi.mqtt_matcher import MQTTMatcher
|
||||||
from hbmqtt.broker import Broker
|
from hbmqtt.broker import Broker
|
||||||
from hbmqtt.client import MQTTClient
|
from hbmqtt.client import MQTTClient
|
||||||
from hbmqtt.mqtt.constants import QOS_1, QOS_0
|
from hbmqtt.mqtt.constants import QOS_1, QOS_0
|
1
cbpi/utils/__init__.py
Normal file
1
cbpi/utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from cbpi.utils.utils import *
|
|
@ -4,7 +4,7 @@ class ComplexEncoder(JSONEncoder):
|
||||||
|
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
|
|
||||||
from core.database.orm_framework import DBModel
|
from cbpi.database.orm_framework import DBModel
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance(obj, DBModel):
|
if isinstance(obj, DBModel):
|
|
@ -1,4 +1,4 @@
|
||||||
from core.utils.encoder import ComplexEncoder
|
from cbpi.utils.encoder import ComplexEncoder
|
||||||
|
|
||||||
__all__ = ['load_config',"json_dumps"]
|
__all__ = ['load_config',"json_dumps"]
|
||||||
|
|
|
@ -4,10 +4,10 @@ from collections import defaultdict
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi_api import *
|
from cbpi.api import *
|
||||||
from voluptuous import Schema
|
from voluptuous import Schema
|
||||||
|
|
||||||
from utils import json_dumps
|
from cbpi.utils import json_dumps
|
||||||
|
|
||||||
|
|
||||||
class CBPiWebSocket:
|
class CBPiWebSocket:
|
||||||
|
@ -22,7 +22,7 @@ class CBPiWebSocket:
|
||||||
@on_event(topic="#")
|
@on_event(topic="#")
|
||||||
async def listen(self, topic, **kwargs):
|
async def listen(self, topic, **kwargs):
|
||||||
data = dict(topic=topic, data=dict(**kwargs))
|
data = dict(topic=topic, data=dict(**kwargs))
|
||||||
self.logger.info("PUSH %s " % data)
|
self.logger.debug("PUSH %s " % data)
|
||||||
self.send(data)
|
self.send(data)
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
|
@ -1,3 +1 @@
|
||||||
cbpi-actor
|
cbpi-actor
|
||||||
cbpi-actor
|
|
||||||
cbpi-actor
|
|
|
@ -1 +0,0 @@
|
||||||
from core.utils.utils import *
|
|
BIN
craftbeerpi.db
BIN
craftbeerpi.db
Binary file not shown.
|
@ -1,34 +0,0 @@
|
||||||
2019-01-04 00:44:35,10
|
|
||||||
2019-01-04 00:44:40,10
|
|
||||||
2019-01-04 00:44:45,10
|
|
||||||
2019-01-04 00:44:50,10
|
|
||||||
2019-01-04 00:44:55,10
|
|
||||||
2019-01-04 00:45:00,10
|
|
||||||
2019-01-04 00:45:05,10
|
|
||||||
2019-01-04 00:45:10,10
|
|
||||||
2019-01-04 00:45:15,10
|
|
||||||
2019-01-04 00:45:20,10
|
|
||||||
2019-01-04 00:45:25,10
|
|
||||||
2019-01-04 00:45:30,10
|
|
||||||
2019-01-04 00:45:35,10
|
|
||||||
2019-01-04 00:45:40,10
|
|
||||||
2019-01-04 00:45:45,10
|
|
||||||
2019-01-04 00:45:50,10
|
|
||||||
2019-01-04 00:45:55,10
|
|
||||||
2019-01-04 00:46:00,10
|
|
||||||
2019-01-04 00:46:05,10
|
|
||||||
2019-01-04 00:46:10,10
|
|
||||||
2019-01-04 00:46:15,10
|
|
||||||
2019-01-04 00:46:20,10
|
|
||||||
2019-01-04 00:46:31,10
|
|
||||||
2019-01-04 00:46:36,10
|
|
||||||
2019-01-04 00:46:41,10
|
|
||||||
2019-01-04 00:46:46,10
|
|
||||||
2019-01-04 00:46:51,10
|
|
||||||
2019-01-04 00:46:56,10
|
|
||||||
2019-01-04 00:47:01,10
|
|
||||||
2019-01-04 00:47:06,10
|
|
||||||
2019-01-04 00:47:11,10
|
|
||||||
2019-01-04 00:47:16,10
|
|
||||||
2019-01-04 00:47:21,10
|
|
||||||
2019-01-04 00:47:26,10
|
|
|
@ -1,86 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
||||||
2019-01-04 00:19:48,10
|
|
||||||
2019-01-04 00:19:53,10
|
|
||||||
2019-01-04 00:20:04,10
|
|
||||||
2019-01-04 00:20:09,10
|
|
||||||
2019-01-04 00:20:14,10
|
|
||||||
2019-01-04 00:20:19,10
|
|
||||||
2019-01-04 00:20:24,10
|
|
||||||
2019-01-04 00:20:29,10
|
|
||||||
2019-01-04 00:20:34,10
|
|
||||||
2019-01-04 00:20:39,10
|
|
||||||
2019-01-04 00:20:44,10
|
|
||||||
2019-01-04 00:20:49,10
|
|
||||||
2019-01-04 00:20:54,10
|
|
||||||
2019-01-04 00:20:59,10
|
|
||||||
2019-01-04 00:38:43,10
|
|
||||||
2019-01-04 00:38:48,10
|
|
||||||
2019-01-04 00:38:53,10
|
|
||||||
2019-01-04 00:38:58,10
|
|
||||||
2019-01-04 00:39:03,10
|
|
||||||
2019-01-04 00:39:08,10
|
|
||||||
2019-01-04 00:39:13,10
|
|
||||||
2019-01-04 00:39:18,10
|
|
||||||
2019-01-04 00:39:23,10
|
|
||||||
2019-01-04 00:39:28,10
|
|
||||||
2019-01-04 00:39:33,10
|
|
||||||
2019-01-04 00:39:38,10
|
|
||||||
2019-01-04 00:39:45,10
|
|
||||||
2019-01-04 00:39:54,10
|
|
||||||
2019-01-04 00:39:59,10
|
|
||||||
2019-01-04 00:40:04,10
|
|
||||||
2019-01-04 00:40:09,10
|
|
||||||
2019-01-04 00:40:14,10
|
|
||||||
2019-01-04 00:40:21,10
|
|
||||||
2019-01-04 00:40:31,10
|
|
||||||
2019-01-04 00:40:36,10
|
|
||||||
2019-01-04 00:40:41,10
|
|
||||||
2019-01-04 00:40:46,10
|
|
||||||
2019-01-04 00:40:51,10
|
|
||||||
2019-01-04 00:40:56,10
|
|
||||||
2019-01-04 00:41:01,10
|
|
||||||
2019-01-04 00:41:06,10
|
|
||||||
2019-01-04 00:41:11,10
|
|
||||||
2019-01-04 00:41:16,10
|
|
||||||
2019-01-04 00:41:21,10
|
|
||||||
2019-01-04 00:41:26,10
|
|
||||||
2019-01-04 00:41:31,10
|
|
||||||
2019-01-04 00:41:36,10
|
|
||||||
2019-01-04 00:41:41,10
|
|
||||||
2019-01-04 00:41:46,10
|
|
||||||
2019-01-04 00:41:51,10
|
|
||||||
2019-01-04 00:41:56,10
|
|
||||||
2019-01-04 00:42:01,10
|
|
||||||
2019-01-04 00:42:06,10
|
|
||||||
2019-01-04 00:42:11,10
|
|
||||||
2019-01-04 00:42:16,10
|
|
||||||
2019-01-04 00:42:21,10
|
|
||||||
2019-01-04 00:42:26,10
|
|
||||||
2019-01-04 00:42:31,10
|
|
||||||
2019-01-04 00:42:36,10
|
|
||||||
2019-01-04 00:42:41,10
|
|
||||||
2019-01-04 00:42:46,10
|
|
||||||
2019-01-04 00:42:51,10
|
|
||||||
2019-01-04 00:42:56,10
|
|
||||||
2019-01-04 00:43:05,10
|
|
||||||
2019-01-04 00:43:10,10
|
|
||||||
2019-01-04 00:43:15,10
|
|
||||||
2019-01-04 00:43:20,10
|
|
||||||
2019-01-04 00:43:25,10
|
|
||||||
2019-01-04 00:43:30,10
|
|
||||||
2019-01-04 00:43:35,10
|
|
||||||
2019-01-04 00:43:40,10
|
|
||||||
2019-01-04 00:43:45,10
|
|
||||||
2019-01-04 00:43:50,10
|
|
||||||
2019-01-04 00:43:55,10
|
|
||||||
2019-01-04 00:44:00,10
|
|
||||||
2019-01-04 00:44:05,10
|
|
||||||
2019-01-04 00:44:10,10
|
|
||||||
2019-01-04 00:44:15,10
|
|
||||||
2019-01-04 00:44:20,10
|
|
||||||
2019-01-04 00:44:25,10
|
|
||||||
2019-01-04 00:44:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,5 +0,0 @@
|
||||||
2019-01-04 00:19:10,10
|
|
||||||
2019-01-04 00:19:15,10
|
|
||||||
2019-01-04 00:19:20,10
|
|
||||||
2019-01-04 00:19:25,10
|
|
||||||
2019-01-04 00:19:30,10
|
|
|
@ -1,23 +0,0 @@
|
||||||
2019-01-02 18:49:55,10
|
|
||||||
2019-01-02 18:49:56,10
|
|
||||||
2019-01-02 18:49:57,10
|
|
||||||
2019-01-02 18:51:25,10
|
|
||||||
2019-01-02 18:51:26,10
|
|
||||||
2019-01-02 18:51:27,10
|
|
||||||
2019-01-02 18:51:28,10
|
|
||||||
2019-01-02 18:51:40,10
|
|
||||||
2019-01-02 18:51:41,10
|
|
||||||
2019-01-02 18:51:42,10
|
|
||||||
2019-01-02 18:51:43,10
|
|
||||||
2019-01-02 18:51:49,10
|
|
||||||
2019-01-02 18:51:50,10
|
|
||||||
2019-01-02 18:51:51,10
|
|
||||||
2019-01-02 18:51:52,10
|
|
||||||
2019-01-02 18:53:09,10
|
|
||||||
2019-01-02 18:53:10,10
|
|
||||||
2019-01-02 18:53:11,10
|
|
||||||
2019-01-02 18:53:12,10
|
|
||||||
2019-01-02 19:03:29,10
|
|
||||||
2019-01-02 19:03:30,10
|
|
||||||
2019-01-02 19:03:31,10
|
|
||||||
2019-01-02 19:03:32,10
|
|
|
@ -1,86 +0,0 @@
|
||||||
2019-01-02 17:05:13,10
|
|
||||||
2019-01-02 17:05:14,10
|
|
||||||
2019-01-02 17:05:15,10
|
|
||||||
2019-01-02 18:02:23,10
|
|
||||||
2019-01-02 18:02:24,10
|
|
||||||
2019-01-02 18:02:25,10
|
|
||||||
2019-01-02 18:02:26,10
|
|
||||||
2019-01-02 18:21:31,10
|
|
||||||
2019-01-02 18:21:32,10
|
|
||||||
2019-01-02 18:21:33,10
|
|
||||||
2019-01-02 18:21:34,10
|
|
||||||
2019-01-02 18:21:47,10
|
|
||||||
2019-01-02 18:21:48,10
|
|
||||||
2019-01-02 18:21:49,10
|
|
||||||
2019-01-02 18:21:50,10
|
|
||||||
2019-01-02 18:21:51,10
|
|
||||||
2019-01-02 18:29:16,10
|
|
||||||
2019-01-02 18:29:17,10
|
|
||||||
2019-01-02 18:29:18,10
|
|
||||||
2019-01-02 18:29:19,10
|
|
||||||
2019-01-02 18:31:37,10
|
|
||||||
2019-01-02 18:31:38,10
|
|
||||||
2019-01-02 18:31:39,10
|
|
||||||
2019-01-02 18:31:40,10
|
|
||||||
2019-01-02 18:32:06,10
|
|
||||||
2019-01-02 18:32:07,10
|
|
||||||
2019-01-02 18:32:08,10
|
|
||||||
2019-01-02 18:32:09,10
|
|
||||||
2019-01-02 18:32:59,10
|
|
||||||
2019-01-02 18:33:00,10
|
|
||||||
2019-01-02 18:33:01,10
|
|
||||||
2019-01-02 18:33:02,10
|
|
||||||
2019-01-02 18:33:33,10
|
|
||||||
2019-01-02 18:33:34,10
|
|
||||||
2019-01-02 18:33:35,10
|
|
||||||
2019-01-02 18:33:36,10
|
|
||||||
2019-01-02 18:33:37,10
|
|
||||||
2019-01-02 18:34:07,10
|
|
||||||
2019-01-02 18:34:08,10
|
|
||||||
2019-01-02 18:34:09,10
|
|
||||||
2019-01-02 18:34:10,10
|
|
||||||
2019-01-02 18:37:59,10
|
|
||||||
2019-01-02 18:38:00,10
|
|
||||||
2019-01-02 18:38:01,10
|
|
||||||
2019-01-02 18:38:02,10
|
|
||||||
2019-01-02 18:38:48,10
|
|
||||||
2019-01-02 18:38:49,10
|
|
||||||
2019-01-02 18:38:50,10
|
|
||||||
2019-01-02 18:38:51,10
|
|
||||||
2019-01-02 18:38:52,10
|
|
||||||
2019-01-02 18:40:45,10
|
|
||||||
2019-01-02 18:40:46,10
|
|
||||||
2019-01-02 18:40:47,10
|
|
||||||
2019-01-02 18:40:48,10
|
|
||||||
2019-01-02 18:40:56,10
|
|
||||||
2019-01-02 18:40:57,10
|
|
||||||
2019-01-02 18:40:58,10
|
|
||||||
2019-01-02 18:40:59,10
|
|
||||||
2019-01-02 18:41:00,10
|
|
||||||
2019-01-02 18:41:50,10
|
|
||||||
2019-01-02 18:41:51,10
|
|
||||||
2019-01-02 18:41:52,10
|
|
||||||
2019-01-02 18:41:53,10
|
|
||||||
2019-01-02 18:43:39,10
|
|
||||||
2019-01-02 18:43:40,10
|
|
||||||
2019-01-02 18:43:41,10
|
|
||||||
2019-01-02 18:43:42,10
|
|
||||||
2019-01-02 18:44:37,10
|
|
||||||
2019-01-02 18:44:38,10
|
|
||||||
2019-01-02 18:44:39,10
|
|
||||||
2019-01-02 18:44:40,10
|
|
||||||
2019-01-02 18:44:41,10
|
|
||||||
2019-01-02 18:45:17,10
|
|
||||||
2019-01-02 18:45:18,10
|
|
||||||
2019-01-02 18:45:19,10
|
|
||||||
2019-01-02 18:45:20,10
|
|
||||||
2019-01-02 18:47:19,10
|
|
||||||
2019-01-02 18:47:20,10
|
|
||||||
2019-01-02 18:47:21,10
|
|
||||||
2019-01-02 18:47:22,10
|
|
||||||
2019-01-02 18:47:23,10
|
|
||||||
2019-01-02 18:49:03,10
|
|
||||||
2019-01-02 18:49:05,10
|
|
||||||
2019-01-02 18:49:06,10
|
|
||||||
2019-01-02 18:49:07,10
|
|
||||||
2019-01-02 18:49:54,10
|
|
|
@ -1,86 +0,0 @@
|
||||||
2019-01-02 11:15:04,10
|
|
||||||
2019-01-02 11:16:21,10
|
|
||||||
2019-01-02 11:16:22,10
|
|
||||||
2019-01-02 11:16:23,10
|
|
||||||
2019-01-02 11:16:24,10
|
|
||||||
2019-01-02 11:16:25,10
|
|
||||||
2019-01-02 11:18:51,10
|
|
||||||
2019-01-02 11:18:52,10
|
|
||||||
2019-01-02 11:18:53,10
|
|
||||||
2019-01-02 11:18:54,10
|
|
||||||
2019-01-02 16:19:57,10
|
|
||||||
2019-01-02 16:19:58,10
|
|
||||||
2019-01-02 16:19:59,10
|
|
||||||
2019-01-02 16:20:00,10
|
|
||||||
2019-01-02 16:20:01,10
|
|
||||||
2019-01-02 16:21:08,10
|
|
||||||
2019-01-02 16:21:09,10
|
|
||||||
2019-01-02 16:21:10,10
|
|
||||||
2019-01-02 16:21:11,10
|
|
||||||
2019-01-02 16:21:25,10
|
|
||||||
2019-01-02 16:21:26,10
|
|
||||||
2019-01-02 16:21:27,10
|
|
||||||
2019-01-02 16:21:28,10
|
|
||||||
2019-01-02 16:22:24,10
|
|
||||||
2019-01-02 16:22:25,10
|
|
||||||
2019-01-02 16:22:26,10
|
|
||||||
2019-01-02 16:22:27,10
|
|
||||||
2019-01-02 16:23:42,10
|
|
||||||
2019-01-02 16:23:43,10
|
|
||||||
2019-01-02 16:23:44,10
|
|
||||||
2019-01-02 16:23:45,10
|
|
||||||
2019-01-02 16:23:46,10
|
|
||||||
2019-01-02 16:24:55,10
|
|
||||||
2019-01-02 16:24:56,10
|
|
||||||
2019-01-02 16:24:57,10
|
|
||||||
2019-01-02 16:24:58,10
|
|
||||||
2019-01-02 16:24:59,10
|
|
||||||
2019-01-02 16:25:20,10
|
|
||||||
2019-01-02 16:25:21,10
|
|
||||||
2019-01-02 16:25:22,10
|
|
||||||
2019-01-02 16:25:23,10
|
|
||||||
2019-01-02 16:25:24,10
|
|
||||||
2019-01-02 16:26:25,10
|
|
||||||
2019-01-02 16:26:26,10
|
|
||||||
2019-01-02 16:26:27,10
|
|
||||||
2019-01-02 16:26:28,10
|
|
||||||
2019-01-02 16:52:03,10
|
|
||||||
2019-01-02 16:52:04,10
|
|
||||||
2019-01-02 16:52:05,10
|
|
||||||
2019-01-02 16:52:06,10
|
|
||||||
2019-01-02 16:52:07,10
|
|
||||||
2019-01-02 16:52:47,10
|
|
||||||
2019-01-02 16:52:48,10
|
|
||||||
2019-01-02 16:52:49,10
|
|
||||||
2019-01-02 16:52:50,10
|
|
||||||
2019-01-02 16:53:19,10
|
|
||||||
2019-01-02 16:53:20,10
|
|
||||||
2019-01-02 16:53:22,10
|
|
||||||
2019-01-02 16:53:23,10
|
|
||||||
2019-01-02 16:53:46,10
|
|
||||||
2019-01-02 16:53:47,10
|
|
||||||
2019-01-02 16:53:48,10
|
|
||||||
2019-01-02 16:53:49,10
|
|
||||||
2019-01-02 17:00:57,10
|
|
||||||
2019-01-02 17:00:58,10
|
|
||||||
2019-01-02 17:00:59,10
|
|
||||||
2019-01-02 17:01:00,10
|
|
||||||
2019-01-02 17:01:06,10
|
|
||||||
2019-01-02 17:01:07,10
|
|
||||||
2019-01-02 17:01:08,10
|
|
||||||
2019-01-02 17:01:09,10
|
|
||||||
2019-01-02 17:02:14,10
|
|
||||||
2019-01-02 17:02:15,10
|
|
||||||
2019-01-02 17:02:16,10
|
|
||||||
2019-01-02 17:02:17,10
|
|
||||||
2019-01-02 17:02:18,10
|
|
||||||
2019-01-02 17:02:34,10
|
|
||||||
2019-01-02 17:02:35,10
|
|
||||||
2019-01-02 17:02:36,10
|
|
||||||
2019-01-02 17:02:37,10
|
|
||||||
2019-01-02 17:02:38,10
|
|
||||||
2019-01-02 17:02:48,10
|
|
||||||
2019-01-02 17:02:49,10
|
|
||||||
2019-01-02 17:02:50,10
|
|
||||||
2019-01-02 17:02:51,10
|
|
||||||
2019-01-02 17:05:12,10
|
|
|
@ -1,86 +0,0 @@
|
||||||
2019-01-01 16:29:39,10
|
|
||||||
2019-01-01 16:29:40,10
|
|
||||||
2019-01-01 16:29:41,10
|
|
||||||
2019-01-01 16:29:42,10
|
|
||||||
2019-01-01 16:31:21,10
|
|
||||||
2019-01-01 16:31:22,10
|
|
||||||
2019-01-01 16:31:23,10
|
|
||||||
2019-01-01 16:31:24,10
|
|
||||||
2019-01-01 16:49:40,10
|
|
||||||
2019-01-01 16:49:41,10
|
|
||||||
2019-01-01 16:49:42,10
|
|
||||||
2019-01-01 16:49:43,10
|
|
||||||
2019-01-01 16:51:23,10
|
|
||||||
2019-01-01 16:51:24,10
|
|
||||||
2019-01-01 16:51:25,10
|
|
||||||
2019-01-01 16:51:26,10
|
|
||||||
2019-01-02 10:46:44,10
|
|
||||||
2019-01-02 10:46:45,10
|
|
||||||
2019-01-02 10:46:46,10
|
|
||||||
2019-01-02 10:46:47,10
|
|
||||||
2019-01-02 10:46:48,10
|
|
||||||
2019-01-02 10:48:16,10
|
|
||||||
2019-01-02 10:48:17,10
|
|
||||||
2019-01-02 10:48:18,10
|
|
||||||
2019-01-02 10:48:19,10
|
|
||||||
2019-01-02 10:48:41,10
|
|
||||||
2019-01-02 10:48:42,10
|
|
||||||
2019-01-02 10:48:43,10
|
|
||||||
2019-01-02 10:48:44,10
|
|
||||||
2019-01-02 10:48:45,10
|
|
||||||
2019-01-02 10:49:30,10
|
|
||||||
2019-01-02 10:49:31,10
|
|
||||||
2019-01-02 10:49:32,10
|
|
||||||
2019-01-02 10:49:33,10
|
|
||||||
2019-01-02 10:49:51,10
|
|
||||||
2019-01-02 10:49:52,10
|
|
||||||
2019-01-02 10:49:53,10
|
|
||||||
2019-01-02 10:49:54,10
|
|
||||||
2019-01-02 10:56:09,10
|
|
||||||
2019-01-02 10:56:10,10
|
|
||||||
2019-01-02 10:56:11,10
|
|
||||||
2019-01-02 10:56:12,10
|
|
||||||
2019-01-02 10:56:35,10
|
|
||||||
2019-01-02 10:56:36,10
|
|
||||||
2019-01-02 10:56:37,10
|
|
||||||
2019-01-02 10:56:38,10
|
|
||||||
2019-01-02 11:01:55,10
|
|
||||||
2019-01-02 11:01:56,10
|
|
||||||
2019-01-02 11:01:57,10
|
|
||||||
2019-01-02 11:01:58,10
|
|
||||||
2019-01-02 11:03:23,10
|
|
||||||
2019-01-02 11:03:24,10
|
|
||||||
2019-01-02 11:03:25,10
|
|
||||||
2019-01-02 11:03:26,10
|
|
||||||
2019-01-02 11:04:47,10
|
|
||||||
2019-01-02 11:04:48,10
|
|
||||||
2019-01-02 11:04:49,10
|
|
||||||
2019-01-02 11:04:50,10
|
|
||||||
2019-01-02 11:05:22,10
|
|
||||||
2019-01-02 11:05:23,10
|
|
||||||
2019-01-02 11:05:24,10
|
|
||||||
2019-01-02 11:05:25,10
|
|
||||||
2019-01-02 11:06:54,10
|
|
||||||
2019-01-02 11:06:55,10
|
|
||||||
2019-01-02 11:06:56,10
|
|
||||||
2019-01-02 11:06:57,10
|
|
||||||
2019-01-02 11:08:16,10
|
|
||||||
2019-01-02 11:08:17,10
|
|
||||||
2019-01-02 11:08:18,10
|
|
||||||
2019-01-02 11:08:19,10
|
|
||||||
2019-01-02 11:09:04,10
|
|
||||||
2019-01-02 11:09:05,10
|
|
||||||
2019-01-02 11:09:06,10
|
|
||||||
2019-01-02 11:09:07,10
|
|
||||||
2019-01-02 11:10:59,10
|
|
||||||
2019-01-02 11:11:00,10
|
|
||||||
2019-01-02 11:11:01,10
|
|
||||||
2019-01-02 11:11:02,10
|
|
||||||
2019-01-02 11:11:03,10
|
|
||||||
2019-01-02 11:14:02,10
|
|
||||||
2019-01-02 11:14:03,10
|
|
||||||
2019-01-02 11:14:04,10
|
|
||||||
2019-01-02 11:14:05,10
|
|
||||||
2019-01-02 11:15:01,10
|
|
||||||
2019-01-02 11:15:02,10
|
|
||||||
2019-01-02 11:15:03,10
|
|
|
@ -6,66 +6,6 @@ aiohttp-session==2.7.0
|
||||||
aiohttp-swagger==1.0.5
|
aiohttp-swagger==1.0.5
|
||||||
aiojobs==0.2.2
|
aiojobs==0.2.2
|
||||||
aiosqlite==0.7.0
|
aiosqlite==0.7.0
|
||||||
alabaster==0.7.12
|
|
||||||
asn1crypto==0.24.0
|
|
||||||
async-timeout==3.0.1
|
|
||||||
asynctest==0.12.2
|
|
||||||
atomicwrites==1.2.1
|
|
||||||
attrs==18.2.0
|
|
||||||
Babel==2.6.0
|
|
||||||
beautifulsoup4==4.6.3
|
|
||||||
bleach==3.0.2
|
|
||||||
bs4==0.0.1
|
|
||||||
cbpi-api==4.0.1
|
|
||||||
CBPiActor1==4.0.3
|
|
||||||
certifi==2018.10.15
|
|
||||||
cffi==1.11.5
|
|
||||||
chardet==3.0.4
|
|
||||||
Click==7.0
|
|
||||||
coverage==4.5.2
|
|
||||||
cryptography==2.3.1
|
cryptography==2.3.1
|
||||||
docopt==0.6.2
|
|
||||||
docutils==0.14
|
|
||||||
gTTS==2.0.1
|
|
||||||
gTTS-token==1.1.3
|
|
||||||
hbmqtt==0.9.4
|
|
||||||
idna==2.7
|
|
||||||
idna-ssl==1.1.0
|
|
||||||
imagesize==1.1.0
|
|
||||||
Jinja2==2.10
|
|
||||||
MarkupSafe==1.0
|
|
||||||
more-itertools==4.3.0
|
|
||||||
multidict==4.4.2
|
|
||||||
packaging==18.0
|
|
||||||
passlib==1.7.1
|
|
||||||
pkginfo==1.4.2
|
|
||||||
pluggy==0.7.1
|
|
||||||
py==1.7.0
|
|
||||||
pycparser==2.19
|
|
||||||
pyfiglet==0.7.6
|
|
||||||
pygame==1.9.4
|
|
||||||
Pygments==2.2.0
|
|
||||||
pync==2.0.3
|
|
||||||
pyparsing==2.3.0
|
|
||||||
pytest==3.8.2
|
|
||||||
pytest-aiohttp==0.3.0
|
|
||||||
python-dateutil==2.7.5
|
|
||||||
pytz==2018.7
|
|
||||||
PyYAML==3.13
|
|
||||||
readme-renderer==24.0
|
|
||||||
requests==2.20.1
|
|
||||||
requests-toolbelt==0.8.0
|
|
||||||
six==1.11.0
|
|
||||||
snowballstemmer==1.2.1
|
|
||||||
Sphinx==1.8.2
|
|
||||||
sphinx-rtd-theme==0.4.2
|
|
||||||
sphinxcontrib-websupport==1.1.0
|
|
||||||
ticket-auth==0.1.4
|
|
||||||
tqdm==4.28.1
|
|
||||||
transitions==0.6.8
|
|
||||||
twine==1.12.1
|
|
||||||
urllib3==1.24.1
|
|
||||||
voluptuous==0.11.5
|
voluptuous==0.11.5
|
||||||
webencodings==0.5.1
|
pyfigle==0.7.6
|
||||||
websockets==6.0
|
|
||||||
yarl==1.2.6
|
|
5
run.py
5
run.py
|
@ -1,4 +1,3 @@
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.cli import main
|
||||||
|
|
||||||
cbpi = CraftBeerPi()
|
main()
|
||||||
cbpi.start()
|
|
37
setup.py
Normal file
37
setup.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(name='cbpi',
|
||||||
|
version='0.0.1',
|
||||||
|
description='CraftBeerPi API',
|
||||||
|
author='Manuel Fritsch',
|
||||||
|
author_email='manuel@craftbeerpi.com',
|
||||||
|
url='http://web.craftbeerpi.com',
|
||||||
|
packages=find_packages(),
|
||||||
|
include_package_data=True,
|
||||||
|
package_data={
|
||||||
|
# If any package contains *.txt or *.rst files, include them:
|
||||||
|
'': ['*.txt', '*.rst', '*.yaml'],
|
||||||
|
'cbpi': ['*','*.txt', '*.rst', '*.yaml']},
|
||||||
|
|
||||||
|
install_requires=[
|
||||||
|
"aiohttp==3.4.4",
|
||||||
|
"aiohttp-auth==0.1.1",
|
||||||
|
"aiohttp-route-decorator==0.1.4",
|
||||||
|
"aiohttp-security==0.4.0",
|
||||||
|
"aiohttp-session==2.7.0",
|
||||||
|
"aiohttp-swagger==1.0.5",
|
||||||
|
"aiojobs==0.2.2",
|
||||||
|
"aiosqlite==0.7.0",
|
||||||
|
"cryptography==2.3.1",
|
||||||
|
"voluptuous==0.11.5",
|
||||||
|
"pyfiglet==0.7.6"
|
||||||
|
],
|
||||||
|
dependency_links=[
|
||||||
|
'https://testpypi.python.org/pypi'
|
||||||
|
],
|
||||||
|
entry_points = {
|
||||||
|
"console_scripts": [
|
||||||
|
"cbpi=cbpi.cli:main",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
|
@ -2,7 +2,7 @@ from unittest import mock
|
||||||
|
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
|
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class ActorTestCase(AioHTTPTestCase):
|
class ActorTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -2,9 +2,9 @@ import time
|
||||||
|
|
||||||
import aiosqlite
|
import aiosqlite
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
from cbpi_api.config import ConfigType
|
from cbpi.api.config import ConfigType
|
||||||
|
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class ConfigTestCase(AioHTTPTestCase):
|
class ConfigTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
|
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class DashboardTestCase(AioHTTPTestCase):
|
class DashboardTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
|
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class IndexTestCase(AioHTTPTestCase):
|
class IndexTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class KettleTestCase(AioHTTPTestCase):
|
class KettleTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
|
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class NotificationTestCase(AioHTTPTestCase):
|
class NotificationTestCase(AioHTTPTestCase):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
|
||||||
from core.craftbeerpi import CraftBeerPi
|
from cbpi.craftbeerpi import CraftBeerPi
|
||||||
|
|
||||||
|
|
||||||
class SensorTestCase(AioHTTPTestCase):
|
class SensorTestCase(AioHTTPTestCase):
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue