diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
index a5d569c..d882427 100644
--- a/.idea/dataSources.local.xml
+++ b/.idea/dataSources.local.xml
@@ -32,5 +32,12 @@
false
*:@
+
+
+
+ master_key
+ false
+ *:@
+
\ No newline at end of file
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index 9b913ae..0cdeb9f 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -78,5 +78,14 @@
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$USER_HOME$/cbpi4_test/2019-08-08-001/craftbeerpi.db
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1dc20ae..e2ce4ea 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,4 +4,7 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 91fd0e5..d0633f5 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,7 +2,38 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13,18 +44,19 @@
-
+
+
-
+
-
+
@@ -57,6 +89,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -66,12 +113,6 @@
-
-
-
-
-
-
@@ -81,43 +122,31 @@
-
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -126,34 +155,54 @@
-
+
-
-
+
+
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
+
+
@@ -163,42 +212,43 @@
- print(
- sensor111
- CBPiWebSocket
- self.ws
- port
- load_plugin_list
- broker
- client
- ok_msg
- mqtt_methods
- HTTP SENSOR
- on_message
- listen
- on_start
- initializer
- plugin_list
- doe
- list
- LIST
- call
- handle_action
- versio
- Sensor1
- array
- log
config
glob
job
notif
loop
+ delte
+ DummyModel
+ /sensor/
+ /sensor
+ Plugin
+ Toogle an actor on or off
+ ConfigType
+ mq
+ create_database
+ create_da
+ db
+ index
+ setup
+ static
+ run
+ register
+ cbpi_ui_plugin
+ /ui-plugin/
+ install_plugin
+ running
+ get_unit
+ list_plugins
+ Loader
+ print
+ loa
@@ -211,44 +261,21 @@
$PROJECT_DIR$/tests
$PROJECT_DIR$/core/extension
$PROJECT_DIR$/core
- $PROJECT_DIR$
$PROJECT_DIR$/cbpi/extension/ui/react/src/views/hardware
- $PROJECT_DIR$/cbpi
+ $PROJECT_DIR$
$PROJECT_DIR$/cbpi/http_endpoints
+ $PROJECT_DIR$/cbpi/config
+ $PROJECT_DIR$/cbpi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -256,34 +283,55 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
@@ -307,323 +355,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -633,23 +365,19 @@
+
+
+
-
-
-
-
-
-
-
@@ -657,6 +385,13 @@
+
+
+
+
+
+
+
@@ -696,7 +431,7 @@
-
+
@@ -741,28 +476,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -863,6 +576,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -884,7 +613,7 @@
-
+
@@ -899,19 +628,19 @@
-
+
-
-
+
+
+
-
@@ -956,7 +685,11 @@
-
+
+
+
+
+
1541288846149
@@ -976,39 +709,39 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -1020,20 +753,20 @@
-
+
-
+
-
-
+
+
-
+
-
+
@@ -1042,11 +775,11 @@
-
+
-
+
@@ -1082,13 +815,9 @@
file://$PROJECT_DIR$/cbpi/craftbeerpi.py
- 45
+ 46
-
- file://$PROJECT_DIR$/cbpi/api/sensor.py
-
-
@@ -1105,297 +834,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -1404,23 +846,350 @@
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cbpi/api/__init__.py b/cbpi/api/__init__.py
index 9b3a8ed..4f02b33 100644
--- a/cbpi/api/__init__.py
+++ b/cbpi/api/__init__.py
@@ -2,8 +2,6 @@ __all__ = ["CBPiActor",
"CBPiExtension",
"Property",
"PropertyType",
- "on_websocket_message",
- "on_mqtt_message",
"on_event",
"on_startup",
"request_mapping",
diff --git a/cbpi/api/decorator.py b/cbpi/api/decorator.py
index 2913918..40750a2 100644
--- a/cbpi/api/decorator.py
+++ b/cbpi/api/decorator.py
@@ -2,7 +2,7 @@ from functools import wraps
from voluptuous import Schema
-__all__ = ["request_mapping", "on_startup", "on_event", "on_mqtt_message", "on_websocket_message", "action", "background_task"]
+__all__ = ["request_mapping", "on_startup", "on_event", "action", "background_task"]
from aiohttp_auth import auth
@@ -55,15 +55,6 @@ def request_mapping(path, name=None, method="GET", auth_required=True, json_sche
validate_json_body
)
-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
@@ -76,29 +67,18 @@ def on_event(topic):
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
@@ -108,7 +88,6 @@ def on_startup(name, order=0):
func.name = name
func.order = order
return func
-
return real_decorator
diff --git a/cbpi/api/exceptions.py b/cbpi/api/exceptions.py
index 77af2f6..acec4ee 100644
--- a/cbpi/api/exceptions.py
+++ b/cbpi/api/exceptions.py
@@ -11,4 +11,4 @@ class SensorException(CBPiException):
pass
class ActorException(CBPiException):
- pass
\ No newline at end of file
+ pass
diff --git a/cbpi/api/sensor.py b/cbpi/api/sensor.py
index 89ef0c3..727c429 100644
--- a/cbpi/api/sensor.py
+++ b/cbpi/api/sensor.py
@@ -1,11 +1,10 @@
-from logging.handlers import RotatingFileHandler
-from time import localtime, strftime
+import logging
+from abc import ABCMeta
from cbpi.api.extension import CBPiExtension
-import logging
-class CBPiSensor(CBPiExtension):
+class CBPiSensor(CBPiExtension, metaclass=ABCMeta):
def __init__(self, *args, **kwds):
CBPiExtension.__init__(self, *args, **kwds)
self.logger = logging.getLogger(__file__)
diff --git a/cbpi/api/step.py b/cbpi/api/step.py
index 2b4e2dc..d252fb3 100644
--- a/cbpi/api/step.py
+++ b/cbpi/api/step.py
@@ -2,7 +2,7 @@ import json
import time
import asyncio
import logging
-from abc import abstractmethod,ABCMeta
+from abc import abstractmethod, ABCMeta
class CBPiSimpleStep(metaclass=ABCMeta):
diff --git a/cbpi/cli.py b/cbpi/cli.py
index 29bed88..6e76cec 100644
--- a/cbpi/cli.py
+++ b/cbpi/cli.py
@@ -1,7 +1,12 @@
import argparse
+import datetime
import logging
+import subprocess
+import sys
+import re
import requests
import yaml
+from cbpi.utils.utils import load_config
from cbpi.craftbeerpi import CraftBeerPi
import os
@@ -59,22 +64,87 @@ def list_plugins():
print("***************************************************")
print("CraftBeerPi 4.x Plugin List")
print("***************************************************")
+ print("")
plugins_yaml = "https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins_v4.yaml"
r = requests.get(plugins_yaml)
-
data = yaml.load(r.content, Loader=yaml.FullLoader)
-
-
for name, value in data.items():
print(name)
+ print("")
+ print("***************************************************")
+def add(package_name):
+
+ if package_name is None:
+ print("Missing Plugin Name: cbpi add --name=")
+ return
+
+ data = subprocess.check_output([sys.executable, "-m", "pip", "install", package_name])
+ data = data.decode('UTF-8')
+
+ patter_already_installed = "Requirement already satisfied: %s" % package_name
+ pattern = "Successfully installed %s-([-0-9a-zA-Z._]*)" % package_name
+
+ match_already_installed = re.search(patter_already_installed, data)
+ match_installed = re.search(pattern, data)
+
+ if match_already_installed is not None:
+ print("Plugin already installed")
+ return False
+
+ if match_installed is None:
+ print(data)
+ print("Faild to install plugin")
+ return False
+
+ version = match_installed.groups()[0]
+ plugins = load_config("./config/plugin_list.txt")
+ if plugins is None:
+ plugins = {}
+ now = datetime.datetime.now()
+ plugins[package_name] = dict(version=version, installation_date=now.strftime("%Y-%m-%d %H:%M:%S"))
+
+ with open('./config/plugin_list.txt', 'w') as outfile:
+ yaml.dump(plugins, outfile, default_flow_style=False)
+
+ print("Plugin %s added" % package_name)
+ return True
+
+
+def remove(package_name):
+ if package_name is None:
+ print("Missing Plugin Name: cbpi add --name=")
+ return
+ data = subprocess.check_output([sys.executable, "-m", "pip", "uninstall", "-y", package_name])
+ data = data.decode('UTF-8')
+
+ pattern = "Successfully uninstalled %s-([-0-9a-zA-Z._]*)" % package_name
+ match_uninstalled = re.search(pattern, data)
+
+ if match_uninstalled is None:
+ print(data)
+ print("Faild to uninstall plugin")
+ return False
+
+ plugins = load_config("./config/plugin_list.txt")
+ if plugins is None:
+ plugins = {}
+
+ if package_name not in plugins:
+ return False
+
+ del plugins[package_name]
+ with open('./config/plugin_list.txt', 'w') as outfile:
+ yaml.dump(plugins, outfile, default_flow_style=False)
+
+ print("Plugin %s removed" % package_name)
+ return True
def main():
parser = argparse.ArgumentParser(description='Welcome to CraftBeerPi 4')
parser.add_argument("action", type=str, help="start,stop,restart,setup,plugins")
-
+ parser.add_argument("--name", type=str, help="Plugin name")
args = parser.parse_args()
-
#logging.basicConfig(level=logging.INFO, filename='./logs/app.log', filemode='a', format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
@@ -94,6 +164,16 @@ def main():
list_plugins()
return
+
+ if args.action == "add":
+
+ add(args.name)
+ return
+
+ if args.action == "remove":
+ remove(args.name)
+ return
+
if args.action == "start":
if check_for_setup() is False:
return
diff --git a/cbpi/config/create_database.sql b/cbpi/config/create_database.sql
index a341e38..9c4d038 100644
--- a/cbpi/config/create_database.sql
+++ b/cbpi/config/create_database.sql
@@ -108,4 +108,9 @@ CREATE TABLE IF NOT EXISTS dummy
id INTEGER PRIMARY KEY NOT NULL,
name VARCHAR(80)
-);
\ No newline at end of file
+);
+
+
+INSERT OR IGNORE INTO config (name, value, type, description, options) VALUES ('TEMP_UNIT', 'F', 'select', 'Temperature Unit', '[{"value": "C", "label": "C"}, {"value": "F", "label": "F"}]');
+INSERT OR IGNORE INTO config (name, value, type, description, options) VALUES ('NAME', 'India Pale Ale1', 'string', 'Brew Name', 'null');
+INSERT OR IGNORE INTO config (name, value, type, description, options) VALUES ('BREWERY_NAME', 'CraftBeerPI', 'string', 'Brewery Name', 'null');
diff --git a/cbpi/config/plugin_list.txt b/cbpi/config/plugin_list.txt
index 142c198..e69de29 100644
--- a/cbpi/config/plugin_list.txt
+++ b/cbpi/config/plugin_list.txt
@@ -1 +0,0 @@
-cbpi-actor
\ No newline at end of file
diff --git a/cbpi/controller/actor_controller.py b/cbpi/controller/actor_controller.py
index 6d7d95d..7cd5278 100644
--- a/cbpi/controller/actor_controller.py
+++ b/cbpi/controller/actor_controller.py
@@ -149,8 +149,7 @@ class ActorController(CRUDController):
pass
async def _pre_delete_callback(self, actor_id):
- #if int(actor_id) not in self.cache:
- # return
+
if self.cache[int(actor_id)].instance is not None:
await self._stop_actor(self.cache[int(actor_id)])
diff --git a/cbpi/controller/dashboard_controller.py b/cbpi/controller/dashboard_controller.py
index 7daff7b..ae68214 100644
--- a/cbpi/controller/dashboard_controller.py
+++ b/cbpi/controller/dashboard_controller.py
@@ -10,6 +10,7 @@ class DashboardController(CRUDController):
name = "Dashboard"
def __init__(self, cbpi):
+ self.caching = False
super(DashboardController, self).__init__(cbpi)
self.cbpi = cbpi
self.logger = logging.getLogger(__name__)
@@ -29,3 +30,7 @@ class DashboardController(CRUDController):
async def move_content(self,content_id, x, y):
await DashboardContentModel.update_coordinates(content_id, x, y)
+
+ async def delete_dashboard(self, dashboard_id):
+ await DashboardContentModel.delete_by_dashboard_id(dashboard_id)
+ await self.model.delete(dashboard_id)
\ No newline at end of file
diff --git a/cbpi/craftbeerpi.py b/cbpi/craftbeerpi.py
index 0d6f263..c230052 100644
--- a/cbpi/craftbeerpi.py
+++ b/cbpi/craftbeerpi.py
@@ -1,5 +1,6 @@
import logging
from os import urandom
+import os
from aiohttp import web
from aiohttp_auth import auth
@@ -231,7 +232,8 @@ class CraftBeerPi():
else:
return web.Response(text="Hello from CraftbeerPi!")
- self.app.add_routes([web.get('/', http_index)])
+
+ self.app.add_routes([web.get('/', http_index), web.static('/static', os.path.join(os.path.dirname(__file__),"static"), show_index=True)])
async def init_serivces(self):
diff --git a/cbpi/extension/comp/__init__.py b/cbpi/extension/comp/__init__.py
index 58ccbeb..e9ae1c2 100644
--- a/cbpi/extension/comp/__init__.py
+++ b/cbpi/extension/comp/__init__.py
@@ -1,7 +1,4 @@
import os
-
-from aiohttp import web
-
from cbpi.api import *
from cbpi.controller.crud_controller import CRUDController
from cbpi.database.orm_framework import DBModel
@@ -22,11 +19,8 @@ class MyComp(CBPiExtension, CRUDController, HttpCrudEndpoints):
def __init__(self, cbpi):
'''
Initializer
-
:param cbpi:
'''
-
-
self.cbpi = cbpi
# register component for http, events
# In addtion the sub folder static is exposed to access static content via http
@@ -35,14 +29,14 @@ class MyComp(CBPiExtension, CRUDController, HttpCrudEndpoints):
@on_event(topic="actor/#")
async def listen(self, **kwargs):
+ # Listen for all actor events
pass
-
@on_event(topic="kettle/+/automatic")
async def listen2(self, **kwargs):
+ # listen for all kettle events which are switching the automatic logic
pass
- #await self.cbpi.bus.fire(topic="actor/%s/toggle" % 1, id=1)
def setup(cbpi):
@@ -54,4 +48,4 @@ def setup(cbpi):
'''
# regsiter the component to the core
cbpi.plugin.register("MyComp", MyComp)
- pass
\ No newline at end of file
+ pass
diff --git a/cbpi/extension/ds18b20/__init__.py b/cbpi/extension/ds18b20/__init__.py
new file mode 100644
index 0000000..55e9a9a
--- /dev/null
+++ b/cbpi/extension/ds18b20/__init__.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+import asyncio
+import threading
+import time
+
+from aiohttp import web
+from cbpi.api import *
+
+import re
+import random
+
+
+def getSensors():
+ try:
+ arr = []
+ for dirname in os.listdir('/sys/bus/w1/devices'):
+ if (dirname.startswith("28") or dirname.startswith("10")):
+ cbpi.app.logger.info("Device %s Found (Family: 28/10, Thermometer on GPIO4 (w1))" % dirname)
+ arr.append(dirname)
+ return arr
+ except:
+ return []
+
+
+class myThread (threading.Thread):
+
+ value = 0
+
+
+ def __init__(self, sensor_name):
+ threading.Thread.__init__(self)
+ self.value = 0
+ self.sensor_name = sensor_name
+ self.runnig = True
+
+ def shutdown(self):
+ pass
+
+ def stop(self):
+ self.runnig = False
+
+ def run(self):
+
+ while self.runnig:
+
+ try:
+ app.logger.info("READ TEMP")
+ ## Test Mode
+ if self.sensor_name is None:
+ return
+ with open('/sys/bus/w1/devices/w1_bus_master1/%s/w1_slave' % self.sensor_name, 'r') as content_file:
+ content = content_file.read()
+ if (content.split('\n')[0].split(' ')[11] == "YES"):
+ temp = float(content.split("=")[-1]) / 1000 # temp in Celcius
+ self.value = temp
+ except:
+ pass
+
+ self.value = random.randint(1,100)
+ time.sleep(4)
+
+class DS18B20(CBPiSensor):
+
+
+ sensor_name = Property.Select("Sensor", getSensors(), description="The OneWire sensor address.")
+ offset = Property.Number("Offset", True, 0, description="Offset which is added to the received sensor data. Positive and negative values are both allowed.")
+ interval = Property.Number(label="interval", configurable=True)
+
+ # Internal runtime variable
+ value = 0
+
+ def init(self):
+ super().init()
+ self.state = True
+ self.t = myThread(self.sensor_name)
+ def shudown():
+ shudown.cb.shutdown()
+
+ shudown.cb = self.t
+
+ self.t.start()
+
+ def get_state(self):
+ return self.state
+
+ def get_value(self):
+
+ return self.value
+
+ def get_unit(self):
+ return "°%s" % self.get_parameter("TEMP_UNIT", "C")
+
+ def stop(self):
+ try:
+ self.t.stop()
+ except:
+ pass
+
+ async def run(self, cbpi):
+ self.value = 0
+ while True:
+ await asyncio.sleep(self.interval)
+ self.value = random.randint(1,101)
+ self.log_data(self.value)
+ await cbpi.bus.fire("sensor/%s/data" % self.id, value=self.value)
+
+
+
+
+def setup(cbpi):
+
+ '''
+ This method is called by the server during startup
+ Here you need to register your plugins at the server
+
+ :param cbpi: the cbpi core
+ :return:
+ '''
+
+ cbpi.plugin.register("DS18B20", DS18B20)
diff --git a/cbpi/extension/ds18b20/config.yaml b/cbpi/extension/ds18b20/config.yaml
new file mode 100644
index 0000000..7f0aa15
--- /dev/null
+++ b/cbpi/extension/ds18b20/config.yaml
@@ -0,0 +1,3 @@
+name: DummySensor
+version: 4
+active: true
\ No newline at end of file
diff --git a/cbpi/extension/dummysensor/__init__.py b/cbpi/extension/dummysensor/__init__.py
index 971c5a9..ba1e743 100644
--- a/cbpi/extension/dummysensor/__init__.py
+++ b/cbpi/extension/dummysensor/__init__.py
@@ -4,13 +4,12 @@ from aiohttp import web
from cbpi.api import *
import re
-
+import random
class CustomSensor(CBPiSensor):
# Custom Properties which will can be configured by the user
- p1 = Property.Number(label="Test")
- p2 = Property.Text(label="Test")
+
interval = Property.Number(label="interval", configurable=True)
# Internal runtime variable
@@ -45,104 +44,10 @@ class CustomSensor(CBPiSensor):
self.value = 0
while True:
await asyncio.sleep(self.interval)
- self.value = self.value + 1
+ self.value = random.randint(1,101)
self.log_data(self.value)
await cbpi.bus.fire("sensor/%s/data" % self.id, value=self.value)
-cache = {}
-
-
-class HTTPSensor(CBPiSensor):
-
- # Custom Properties which will can be configured by the user
-
- key = Property.Text(label="Key", configurable=True)
-
- def init(self):
- super().init()
-
- self.state = True
-
- def get_state(self):
- return self.state
-
- def get_value(self):
-
- return self.value
-
- def stop(self):
- pass
-
- async def run(self, cbpi):
- self.value = 0
- while True:
- await asyncio.sleep(1)
-
- try:
- value = cache.pop(self.key, None)
-
- if value is not None:
- self.log_data(value)
- await cbpi.bus.fire("sensor/%s/data" % self.id, value=value)
- except Exception as e:
- print(e)
- pass
-
-class HTTPSensorEndpoint(CBPiExtension):
-
-
- def __init__(self, cbpi):
- '''
- Initializer
-
- :param cbpi:
- '''
- self.pattern_check = re.compile("^[a-zA-Z0-9,.]{0,10}$")
-
- self.cbpi = cbpi
- # register component for http, events
- # In addtion the sub folder static is exposed to access static content via http
- self.cbpi.register(self, "/httpsensor")
-
-
- @request_mapping(path="/{key}/{value}", auth_required=False)
- async def http_new_value2(self, request):
- """
- ---
- description: Kettle Heater on
- tags:
- - HttpSensor
- parameters:
- - name: "key"
- in: "path"
- description: "Sensor Key"
- required: true
- type: "string"
- - name: "value"
- in: "path"
- description: "Value"
- required: true
- type: "integer"
- format: "int64"
- responses:
- "204":
- description: successful operation
- """
-
- global cache
- key = request.match_info['key']
- value = request.match_info['value']
- if self.pattern_check.match(key) is None:
- return web.json_response(status=422, data={'error': "Key not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
-
- if self.pattern_check.match(value) is None:
- return web.json_response(status=422, data={'error': "Data not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
-
- print("HTTP SENSOR ", key, value)
- cache[key] = value
-
- return web.Response(status=204)
-
def setup(cbpi):
@@ -153,6 +58,5 @@ def setup(cbpi):
:param cbpi: the cbpi core
:return:
'''
- cbpi.plugin.register("HTTPSensor", HTTPSensor)
- cbpi.plugin.register("HTTPSensorEndpoint", HTTPSensorEndpoint)
+
cbpi.plugin.register("CustomSensor", CustomSensor)
diff --git a/cbpi/extension/httpsensor/__init__.py b/cbpi/extension/httpsensor/__init__.py
new file mode 100644
index 0000000..19c65ba
--- /dev/null
+++ b/cbpi/extension/httpsensor/__init__.py
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+import asyncio
+from aiohttp import web
+from cbpi.api import *
+
+import re
+import random
+
+
+cache = {}
+
+
+class HTTPSensor(CBPiSensor):
+
+ # Custom Properties which will can be configured by the user
+
+ key = Property.Text(label="Key", configurable=True)
+
+ def init(self):
+ super().init()
+
+ self.state = True
+
+ def get_state(self):
+ return self.state
+
+ def get_value(self):
+
+ return self.value
+
+ def stop(self):
+ pass
+
+ async def run(self, cbpi):
+ self.value = 0
+ while True:
+ await asyncio.sleep(1)
+
+ try:
+ value = cache.pop(self.key, None)
+
+ if value is not None:
+ self.log_data(value)
+ await cbpi.bus.fire("sensor/%s/data" % self.id, value=value)
+ except Exception as e:
+ print(e)
+ pass
+
+class HTTPSensorEndpoint(CBPiExtension):
+
+
+ def __init__(self, cbpi):
+ '''
+ Initializer
+
+ :param cbpi:
+ '''
+ self.pattern_check = re.compile("^[a-zA-Z0-9,.]{0,10}$")
+
+ self.cbpi = cbpi
+ # register component for http, events
+ # In addtion the sub folder static is exposed to access static content via http
+ self.cbpi.register(self, "/httpsensor")
+
+
+ @request_mapping(path="/{key}/{value}", auth_required=False)
+ async def http_new_value2(self, request):
+ """
+ ---
+ description: Kettle Heater on
+ tags:
+ - HttpSensor
+ parameters:
+ - name: "key"
+ in: "path"
+ description: "Sensor Key"
+ required: true
+ type: "string"
+ - name: "value"
+ in: "path"
+ description: "Value"
+ required: true
+ type: "integer"
+ format: "int64"
+ responses:
+ "204":
+ description: successful operation
+ """
+
+ global cache
+ key = request.match_info['key']
+ value = request.match_info['value']
+ if self.pattern_check.match(key) is None:
+ return web.json_response(status=422, data={'error': "Key not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
+
+ if self.pattern_check.match(value) is None:
+ return web.json_response(status=422, data={'error': "Data not matching pattern ^[a-zA-Z0-9,.]{0,10}$"})
+
+ print("HTTP SENSOR ", key, value)
+ cache[key] = value
+
+ return web.Response(status=204)
+
+
+def setup(cbpi):
+
+ '''
+ This method is called by the server during startup
+ Here you need to register your plugins at the server
+
+ :param cbpi: the cbpi core
+ :return:
+ '''
+ cbpi.plugin.register("HTTPSensor", HTTPSensor)
+ cbpi.plugin.register("HTTPSensorEndpoint", HTTPSensorEndpoint)
+
diff --git a/cbpi/extension/httpsensor/config.yaml b/cbpi/extension/httpsensor/config.yaml
new file mode 100644
index 0000000..7f0aa15
--- /dev/null
+++ b/cbpi/extension/httpsensor/config.yaml
@@ -0,0 +1,3 @@
+name: DummySensor
+version: 4
+active: true
\ No newline at end of file
diff --git a/cbpi/http_endpoints/http_dashboard.py b/cbpi/http_endpoints/http_dashboard.py
index 03a2aca..26ad9ed 100644
--- a/cbpi/http_endpoints/http_dashboard.py
+++ b/cbpi/http_endpoints/http_dashboard.py
@@ -118,7 +118,9 @@ class DashBoardHttpEndpoints(HttpCrudEndpoints):
"204":
description: successful operation
"""
- return await super().http_delete_one(request)
+ id = request.match_info['id']
+ await self.cbpi.dashboard.delete_dashboard(id)
+ return web.Response(status=204)
@request_mapping(path="/{id:\d+}/content", auth_required=False)
async def get_content(self, request):
diff --git a/cbpi/http_endpoints/http_sensor.py b/cbpi/http_endpoints/http_sensor.py
index c1b319b..76705f1 100644
--- a/cbpi/http_endpoints/http_sensor.py
+++ b/cbpi/http_endpoints/http_sensor.py
@@ -180,9 +180,9 @@ class SensorHttpEndpoints(HttpCrudEndpoints):
"""
---
- description: Toogle an actor on or off
+ description: Execute action on sensor
tags:
- - Actor
+ - Sensor
parameters:
- name: "id"
in: "path"
diff --git a/cbpi/static/splash.png b/cbpi/static/splash.png
new file mode 100644
index 0000000..68086b5
Binary files /dev/null and b/cbpi/static/splash.png differ
diff --git a/cbpi/static/test.html b/cbpi/static/test.html
new file mode 100644
index 0000000..94782b0
--- /dev/null
+++ b/cbpi/static/test.html
@@ -0,0 +1,17 @@
+
+
+
+
+ CraftBeerPi 4.0
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cbpi/utils/utils.py b/cbpi/utils/utils.py
index e4c34a4..8673080 100644
--- a/cbpi/utils/utils.py
+++ b/cbpi/utils/utils.py
@@ -7,11 +7,13 @@ import yaml
def load_config(fname):
+
try:
with open(fname, 'rt') as f:
- data = yaml.load(f)
+ data = yaml.load(f, Loader=yaml.FullLoader)
return data
except Exception as e:
+ print(e)
pass
def json_dumps(obj):
diff --git a/cbpi_cloud/default_broker.yaml b/cbpi_cloud/default_broker.yaml
deleted file mode 100644
index c7d9dc7..0000000
--- a/cbpi_cloud/default_broker.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-listeners:
- default:
- type: tcp
- bind: 0.0.0.0:1883
-sys_interval: 20
-auth:
- allow-anonymous: true
-plugins:
- - auth_file
- - auth_anonymous
-topic-check:
- enabled': True
- plugins':
- - topic_taboo
\ No newline at end of file
diff --git a/cbpi_cloud/repo/plugins.yaml b/cbpi_cloud/repo/plugins.yaml
deleted file mode 100644
index 17a2d68..0000000
--- a/cbpi_cloud/repo/plugins.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-SampleActor:
- description: A sample Actor for CraftBeerPi
- api: 4.0
- author: CraftBeerPi11
- pip: requests
- repo_url: https://github.com/craftbeerpi/sample_actor
-
-SampleActor2:
- description: A sample Actor2 for CraftBeerPi
- api: 4.0
- author: CraftBeerPi
- pip: requests
- repo_url: https://github.com/craftbeerpi/sample_actor
diff --git a/cbpi_cloud/run.py b/cbpi_cloud/run.py
deleted file mode 100644
index 294ea2f..0000000
--- a/cbpi_cloud/run.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import yaml
-from aiohttp import web
-
-
-def load_yaml():
- try:
- with open('./repo/plugins.yaml', 'rt') as f:
- data = yaml.load(f)
- return data
- except Exception as e:
- print(e)
- pass
-
-data = load_yaml()
-
-for k, v in data.items():
- del v["pip"]
-data2 = load_yaml()
-
-
-async def check(request):
- peername = request.transport.get_extra_info('peername')
- if peername is not None:
- host, port = peername
- print(host, port)
- data = await request.json()
- print(data)
- return web.json_response(data=dict(latestversion="4.0.0.3"))
-
-async def reload_yaml(request):
- global data, data2
-
- file = load_yaml()
- for k, v in file.items():
- del v["pip"]
- data = file
- data2 = load_yaml()
-
- return web.json_response(data=data2)
-
-async def get_list(request):
- print("Request List")
- return web.json_response(data=data)
-
-async def get_package_name(request):
- print("Request Package")
- name = request.match_info.get('plugin_name', None)
- if name in data2:
- package_name = data2[name]["pip"]
- else:
- package_name = None
- return web.json_response(data=dict(package_name=package_name))
-
-
-app = web.Application()
-app.add_routes([
- web.get('/list', get_list),
- web.post('/check', check),
- web.get('/reload', reload_yaml),
- web.get('/get/{plugin_name}', get_package_name)])
-
-web.run_app(app, port=2202)
diff --git a/config/plugin_list.txt b/config/plugin_list.txt
index 92f3cdc..0967ef4 100644
--- a/config/plugin_list.txt
+++ b/config/plugin_list.txt
@@ -1,11 +1 @@
-cbpi-actor:
- api: 4.0
- author: CraftBeerPi11
- description: A sample Actor for CraftBeerPi
- repo_url: https://github.com/craftbeerpi/sample_actor
-cbpi-ui:
- api: 4.0
- author: CraftBeerPi
- description: A sample Actor2 for CraftBeerPi
- repo_url: https://github.com/craftbeerpi/sample_actor
-
+{}
diff --git a/craftbeerpi.db b/craftbeerpi.db
index 9c91416..600db5b 100644
Binary files a/craftbeerpi.db and b/craftbeerpi.db differ
diff --git a/sample.py b/sample.py
index c32859e..249930b 100644
--- a/sample.py
+++ b/sample.py
@@ -1,72 +1,19 @@
import datetime
-import glob
-import json
-import logging
-from logging.handlers import RotatingFileHandler
-from time import strftime, localtime
-import pandas as pd
-import matplotlib.pyplot as plt
-sid = 2
+import yaml
+from cbpi.utils.utils import load_config
+
+package_name = "test222"
+
+with open("./config/plugin_list.txt", 'rt') as f:
+ print(f)
+ plugins = yaml.load(f)
+ if plugins is None:
+ plugins = {}
-data_logger = logging.getLogger('cbpi.sensor.%s' % sid)
-data_logger.propagate = False
-data_logger.setLevel(logging.DEBUG)
-handler = RotatingFileHandler('./logs/sensor_%s.log' % sid, maxBytes=100_000, backupCount=10)
-data_logger.addHandler(handler)
-import random
+now = datetime.datetime.now()
-start = datetime.datetime.now()
-'''
-v = random.randint(50,60)
-for i in range(5760):
- d = start + datetime.timedelta(seconds=6*i)
- formatted_time = d.strftime("%Y-%m-%d %H:%M:%S")
- if i % 750 == 0:
- v = random.randint(50,60)
- data_logger.info("%s,%s" % (formatted_time, v))
-
-
-'''
-def dateparse (time_in_secs):
- return datetime.datetime.strptime(time_in_secs, '%Y-%m-%d %H:%M:%S')
-
-all_filenames = glob.glob('./logs/sensor_1.log*')
-all_filenames.sort()
-
-
-all_filenames2 = glob.glob('./logs/sensor_2.log*')
-all_filenames2.sort()
-
-combined_csv = pd.concat([pd.read_csv(f, parse_dates=True, date_parser=dateparse, index_col='DateTime', names=['DateTime', 'Sensor1'], header=None) for f in all_filenames])
-combined_csv2 = pd.concat([pd.read_csv(f, parse_dates=True, date_parser=dateparse, index_col='DateTime', names=['DateTime', 'Sensor2'], header=None) for f in all_filenames2])
-
-
-print(combined_csv)
-print(combined_csv2)
-
-
-m2 = pd.merge(combined_csv, combined_csv2, how='inner', left_index=True, right_index=True)
-
-print(m2)
-
-m2.plot()
-
-m2.plot(y=['Sensor1','Sensor2'])
-
-ts = combined_csv.Sensor1.resample('5000s').max()
-
-#ts.plot(y='Sensor1')
-
-i = 0
-def myconverter(o):
- if isinstance(o, datetime.datetime):
- return o.__str__()
-
-
-
-data = {"time": ts.index.tolist(), "data": ts.tolist()}
-s1 = json.dumps(data, default = myconverter)
-
-plt.show()
+plugins[package_name] = dict(version="1.0", installation_date=now.strftime("%Y-%m-%d %H:%M:%S"))
+with open('./config/plugin_list.txt', 'w') as outfile:
+ yaml.dump(plugins, outfile, default_flow_style=False)
diff --git a/setup.py b/setup.py
index b443fae..2499821 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
setup(name='cbpi',
- version='4.0.0.4',
+ version='4.0.0.5',
description='CraftBeerPi',
author='Manuel Fritsch',
author_email='manuel@craftbeerpi.com',
diff --git a/tests/test_cli.py b/tests/test_cli.py
new file mode 100644
index 0000000..1e41833
--- /dev/null
+++ b/tests/test_cli.py
@@ -0,0 +1,20 @@
+import logging
+import unittest
+
+from cli import add, remove, list_plugins
+
+logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
+
+
+class CLITest(unittest.TestCase):
+
+ def test_install(self):
+ assert add("cbpi4-ui-plugin") == True
+ assert add("cbpi4-ui-plugin") == False
+ assert remove("cbpi4-ui-plugin") == True
+
+ def test_list(self):
+ list_plugins()
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file