changes for ui

This commit is contained in:
manuel83 2019-01-14 07:33:59 +01:00
parent d0b751a0d4
commit 8cf373c993
13 changed files with 844 additions and 408 deletions

File diff suppressed because it is too large Load diff

View file

@ -26,9 +26,6 @@ def create_home_folder_structure():
def main(): def main():
#import sys
#arg1, arg2 = sys.argv[1], sys.argv[2]
create_home_folder_structure() create_home_folder_structure()
create_plugin_file() create_plugin_file()

View file

@ -54,7 +54,7 @@ class ActorController(CRUDController):
await self.cbpi.bus.fire(topic="actor/%s/stopped" % actor.id, id=actor.id) await self.cbpi.bus.fire(topic="actor/%s/stopped" % actor.id, id=actor.id)
@on_event(topic="actor/+/switch/on") @on_event(topic="actor/+/switch/on")
async def on(self, actor_id, future: Future, power=100, **kwargs) -> None: async def on(self, actor_id, power=100, **kwargs) -> None:
""" """
Method to switch an actor on. Method to switch an actor on.
Supporting Event Topic "actor/+/on" Supporting Event Topic "actor/+/on"
@ -70,10 +70,9 @@ class ActorController(CRUDController):
if actor_id in self.cache: if actor_id in self.cache:
self.logger.debug("ON %s" % actor_id) self.logger.debug("ON %s" % actor_id)
actor = self.cache[actor_id].instance actor = self.cache[actor_id].instance
await self.cbpi.bus.fire("actor/%s/on/ok" % actor_id)
actor.on(power) actor.on(power)
await self.cbpi.bus.fire("actor/%s/on/ok" % actor_id)
future.set_result("OK")
@on_event(topic="actor/+/toggle") @on_event(topic="actor/+/toggle")
async def toggle(self, actor_id, power=100, **kwargs) -> None: async def toggle(self, actor_id, power=100, **kwargs) -> None:
@ -91,9 +90,13 @@ class ActorController(CRUDController):
if actor_id in self.cache: if actor_id in self.cache:
actor = self.cache[actor_id].instance actor = self.cache[actor_id].instance
if actor.state is True: if actor.state is True:
actor.off()
await self.off(actor_id=actor_id)
else: else:
actor.on()
await self.on(actor_id=actor_id)
@on_event(topic="actor/+/off") @on_event(topic="actor/+/off")
@ -111,6 +114,7 @@ class ActorController(CRUDController):
if actor_id in self.cache: if actor_id in self.cache:
actor = self.cache[actor_id].instance actor = self.cache[actor_id].instance
actor.off() actor.off()
await self.cbpi.bus.fire("actor/%s/off/ok" % actor_id)
@on_event(topic="actor/+/action") @on_event(topic="actor/+/action")
async def call_action(self, actor_id, data, **kwargs) -> None: async def call_action(self, actor_id, data, **kwargs) -> None:

View file

@ -36,8 +36,6 @@ from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@web.middleware @web.middleware
async def error_middleware(request, handler): async def error_middleware(request, handler):
try: try:
@ -46,6 +44,7 @@ async def error_middleware(request, handler):
return response return response
message = response.message message = response.message
except web.HTTPException as ex: except web.HTTPException as ex:
print(ex)
if ex.status != 404: if ex.status != 404:
raise raise
message = ex.reason message = ex.reason
@ -60,7 +59,6 @@ class CraftBeerPi():
def __init__(self): def __init__(self):
self.static_config = load_config("./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")
@ -71,15 +69,18 @@ class CraftBeerPi():
self._setup_shutdownhook() self._setup_shutdownhook()
self.initializer = [] self.initializer = []
self.bus = CBPiEventBus(self.app.loop, self) self.bus = CBPiEventBus(self.app.loop, self)
self.ws = CBPiWebSocket(self)
self.job = JobController(self) self.job = JobController(self)
self.config = ConfigController(self)
self.ws = CBPiWebSocket(self)
self.translation = TranslationController(self) self.translation = TranslationController(self)
self.actor = ActorController(self) self.actor = ActorController(self)
self.sensor = SensorController(self) self.sensor = SensorController(self)
self.plugin = PluginController(self) self.plugin = PluginController(self)
self.system = SystemController(self) self.system = SystemController(self)
self.config = ConfigController(self)
self.kettle = KettleController(self) self.kettle = KettleController(self)
self.step = StepController(self) self.step = StepController(self)
self.dashboard = DashboardController(self) self.dashboard = DashboardController(self)
@ -97,6 +98,7 @@ class CraftBeerPi():
def _setup_shutdownhook(self): def _setup_shutdownhook(self):
self.shutdown = False self.shutdown = False
async def on_cleanup(app): async def on_cleanup(app):
self.shutdown = True self.shutdown = True
@ -158,6 +160,7 @@ class CraftBeerPi():
} }
switcher[http_method]() switcher[http_method]()
print("ADDD ", routes)
if url_prefix != "/": if url_prefix != "/":
logger.debug("URL Prefix: %s " % (url_prefix,)) logger.debug("URL Prefix: %s " % (url_prefix,))
sub = web.Application() sub = web.Application()
@ -166,6 +169,7 @@ class CraftBeerPi():
sub.add_routes([web.static('/static', static, show_index=False)]) sub.add_routes([web.static('/static', static, show_index=False)])
self.app.add_subapp(url_prefix, sub) self.app.add_subapp(url_prefix, sub)
else: else:
print("ADDD ", routes)
self.app.add_routes(routes) self.app.add_routes(routes)
def _swagger_setup(self): def _swagger_setup(self):

View file

@ -115,6 +115,8 @@ class CBPiEventBus(object):
futures = {} futures = {}
print("FIRE",topic, kwargs)
async def wait(futures): async def wait(futures):
if(len(futures) > 0): if(len(futures) > 0):
await asyncio.wait(futures.values()) await asyncio.wait(futures.values())

View file

@ -1,16 +1,15 @@
import asyncio import asyncio
import logging from aiohttp import web
import random
from cbpi.api import * from cbpi.api import *
class CustomSensor(CBPiSensor): class CustomSensor(CBPiSensor):
# Custom Properties which will can be configured by the user # Custom Properties which will can be configured by the user
p1 = Property.Number(label="Test") p1 = Property.Number(label="Test")
p2 = Property.Text(label="Test") p2 = Property.Text(label="Test")
interval = Property.Number(label="interval") interval = Property.Number(label="interval", configurable=True)
# Internal runtime variable # Internal runtime variable
value = 0 value = 0
@ -44,10 +43,90 @@ class CustomSensor(CBPiSensor):
self.log_data(10) self.log_data(10)
self.value = self.value + 1 self.value = self.value + 1
await cbpi.bus.fire("sensor/%s" % self.id, value=self.value) await cbpi.bus.fire("sensor/%s/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" % self.id, value=value)
except:
pass
class HTTPSensorEndpoint(CBPiExtension):
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
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
"""
print("HALLO")
global cache
key = request.match_info['key']
value = request.match_info['value']
cache[key] = value
print(cache)
return web.Response(status=204)
def setup(cbpi): def setup(cbpi):
@ -59,5 +138,6 @@ def setup(cbpi):
:param cbpi: the cbpi core :param cbpi: the cbpi core
:return: :return:
''' '''
cbpi.plugin.register("HTTPSensor", HTTPSensor)
cbpi.plugin.register("HTTPSensorEndpoint", HTTPSensorEndpoint)
cbpi.plugin.register("CustomSensor", CustomSensor) cbpi.plugin.register("CustomSensor", CustomSensor)

View file

@ -33,18 +33,9 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
description: Switch actor on description: Switch actor on
tags: tags:
- Actor - Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses: responses:
"204": "204":
description: successful operation description: successful operation
"405":
description: invalid HTTP Met
""" """
return await super().http_get_all(request) return await super().http_get_all(request)
@ -74,7 +65,7 @@ class ActorHttpEndpoints(HttpCrudEndpoints):
async def http_add(self, request): async def http_add(self, request):
""" """
--- ---
description: Get one Actor description: add one Actor
tags: tags:
- Actor - Actor
parameters: parameters:

View file

@ -7,6 +7,146 @@ auth = False
class KettleHttpEndpoints(HttpCrudEndpoints): class KettleHttpEndpoints(HttpCrudEndpoints):
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Get all kettles
tags:
- Kettle
responses:
"204":
description: successful operation
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get Kettle by Id
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: add a kettle
tags:
- Kettle
parameters:
- in: body
name: body
description: Created an kettle
required: false
schema:
type: object
properties:
name:
type: string
sensor:
type: "integer"
format: "int64"
heater:
type: "integer"
format: "int64"
agitator:
type: "integer"
format: "int64"
target_temp:
type: "integer"
format: "int64"
logic:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update a kettle
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Created an kettle
required: false
schema:
type: object
properties:
name:
type: string
sensor:
type: "integer"
format: "int64"
heater:
type: "integer"
format: "int64"
agitator:
type: "integer"
format: "int64"
target_temp:
type: "integer"
format: "int64"
logic:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete a kettle
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
def __init__(self, cbpi): def __init__(self, cbpi):
super().__init__(cbpi) super().__init__(cbpi)
@ -15,37 +155,149 @@ class KettleHttpEndpoints(HttpCrudEndpoints):
@request_mapping(path="/{id:\d+}/automatic", auth_required=False) @request_mapping(path="/{id:\d+}/automatic", auth_required=False)
async def http_automatic(self, request): async def http_automatic(self, request):
"""
---
description: Toggle Automatic
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
await self.controller.toggle_automtic(int(request.match_info['id'])) await self.controller.toggle_automtic(int(request.match_info['id']))
return web.Response(status=204) return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/on", auth_required=False) @request_mapping(path="/{id:\d+}/heater/on", auth_required=False)
async def http_heater_on(self, request): async def http_heater_on(self, request):
"""
---
description: Kettle Heater on
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
await self.controller.heater_on(int(request.match_info['id'])) await self.controller.heater_on(int(request.match_info['id']))
return web.Response(status=204) return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/off", auth_required=False) @request_mapping(path="/{id:\d+}/heater/off", auth_required=False)
async def http_heater_off(self, request): async def http_heater_off(self, request):
"""
---
description: Kettle Heater off
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
await self.controller.heater_off(int(request.match_info['id'])) await self.controller.heater_off(int(request.match_info['id']))
return web.Response(status=204) return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/on", auth_required=False) @request_mapping(path="/{id:\d+}/agitator/on", auth_required=False)
async def http_agitator_on(self, request): async def http_agitator_on(self, request):
"""
---
description: Kettle Agitator on
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
await self.controller.agitator_on(int(request.match_info['id'])) await self.controller.agitator_on(int(request.match_info['id']))
return web.Response(status=204) return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/off", auth_required=False) @request_mapping(path="/{id:\d+}/agitator/off", auth_required=False)
async def http_agitator_off(self, request): async def http_agitator_off(self, request):
"""
---
description: Kettle Agitator off
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
await self.controller.agitator_off(int(request.match_info['id'])) await self.controller.agitator_off(int(request.match_info['id']))
return web.Response(status=204) return web.Response(status=204)
@request_mapping(path="/{id:\d+}/targettemp", auth_required=False) @request_mapping(path="/{id:\d+}/targettemp", auth_required=False)
async def http_taget_temp(self, request): async def http_taget_temp(self, request):
"""
---
description: Get Target Temp of kettle
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
kettle_id = int(request.match_info['id']) kettle_id = int(request.match_info['id'])
temp = await self.controller.get_traget_temp(kettle_id) temp = await self.controller.get_traget_temp(kettle_id)
return web.json_response(data=dict(target_temp=temp, kettle_id=kettle_id)) return web.json_response(data=dict(target_temp=temp, kettle_id=kettle_id))
@request_mapping(path="/{id:\d+}/temp", auth_required=False) @request_mapping(path="/{id:\d+}/temp", auth_required=False)
async def http_temp(self, request): async def http_temp(self, request):
"""
---
description: Get Temp of kettle
tags:
- Kettle
parameters:
- name: "id"
in: "path"
description: "Kettle ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
kettle_id = int(request.match_info['id']) kettle_id = int(request.match_info['id'])
temp = await self.controller.get_temp(kettle_id) temp = await self.controller.get_temp(kettle_id)
return web.json_response(data=dict(temp=temp, kettle_id=kettle_id)) return web.json_response(data=dict(temp=temp, kettle_id=kettle_id))

View file

@ -23,7 +23,7 @@ class ComplexEncoder(JSONEncoder):
#elif callable(getattr(obj, "reprJSON")): #elif callable(getattr(obj, "reprJSON")):
# return obj.reprJSON() # return obj.reprJSON()
elif isinstance(obj, DBModel): elif isinstance(obj, DBModel):
return None return obj.__dict__
#elif hasattr(obj, "callback"): #elif hasattr(obj, "callback"):
# return obj() # return obj()
else: else:

View file

@ -1,4 +1,5 @@
import logging import logging
import re
import weakref import weakref
from collections import defaultdict from collections import defaultdict
@ -19,12 +20,28 @@ class CBPiWebSocket:
self.cbpi.app.add_routes([web.get('/ws', self.websocket_handler)]) self.cbpi.app.add_routes([web.get('/ws', self.websocket_handler)])
self.cbpi.bus.register_object(self) self.cbpi.bus.register_object(self)
@on_event(topic="#") #if self.cbpi.config.static.get("ws_push_all", False):
#self.cbpi.bus.register("#", self.listen)
self.patters = {}
#self.add_mapper("(actor)\/([\d])\/(on|toggle|off)\/(ok)$", self.map_actor)
def add_mapper(self, pattern, method):
self.patters[re.compile(pattern)] = method
async def map_actor(self, regex_result, **kwargs):
actor_id = int(regex_result.group(2))
return dict(topic="ACTOR_UPDATE", data=await self.cbpi.actor.get_one(actor_id))
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.debug("PUSH %s " % data) self.logger.debug("PUSH %s " % data)
self.send(data) self.send(data)
def send(self, data): def send(self, data):
self.logger.debug("broadcast to ws clients. Data: %s" % data) self.logger.debug("broadcast to ws clients. Data: %s" % data)
for ws in self._clients: for ws in self._clients:

View file

@ -10,3 +10,5 @@ port: 8080
username: cbpi username: cbpi
password: 123 password: 123
ws_push_all: true

Binary file not shown.

13
sample.py Normal file
View file

@ -0,0 +1,13 @@
import re
pattern = "(actor)\/([\d])\/(on|toggle|off)$"
p = re.compile(pattern)
result = p.match("actor/1/toggle")
print(result, result.group(3))