"notificaton added"

This commit is contained in:
Manuel Fritsch 2021-03-07 22:11:25 +01:00
parent 0371e74b4a
commit 51c8f82834
12 changed files with 135 additions and 34 deletions

View file

@ -1 +1 @@
__version__ = "4.0.0.29" __version__ = "4.0.0.30"

View file

@ -141,4 +141,13 @@ class Config:
def __str__(self): def __str__(self):
return "....name={} value={}".format(self.name, self.value) return "....name={} value={}".format(self.name, self.value)
def to_dict(self): def to_dict(self):
return dict(name=self.name, value=self.value, type=self.type.value, description=self.description, options=self.options) return dict(name=self.name, value=self.value, type=self.type.value, description=self.description, options=self.options)
@dataclass
class NotificationAction:
label: str
method: Any = None
id: str = None
def to_dict(self):
return dict(id=self.id, label=self.label)

View file

@ -117,7 +117,6 @@ class BasicController:
return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types()} return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types()}
async def add(self, item): async def add(self, item):
print(item)
logging.info("{} Add".format(self.name)) logging.info("{} Add".format(self.name))
item.id = shortuuid.uuid() item.id = shortuuid.uuid()
self.data.append(item) self.data.append(item)

View file

@ -4,6 +4,8 @@ import os
from os import listdir from os import listdir
from os.path import isfile, join from os.path import isfile, join
from voluptuous.schema_builder import message
class DashboardController: class DashboardController:
@ -29,6 +31,7 @@ class DashboardController:
async def add_content(self, dashboard_id, data): async def add_content(self, dashboard_id, data):
with open(self.path, 'w') as outfile: with open(self.path, 'w') as outfile:
json.dump(data, outfile, indent=4, sort_keys=True) json.dump(data, outfile, indent=4, sort_keys=True)
self.cbpi.notify(title="Dashboard", message="Saved Successfully", type="success")
return {"status": "OK"} return {"status": "OK"}
async def delete_content(self, dashboard_id): async def delete_content(self, dashboard_id):

View file

@ -0,0 +1,42 @@
import asyncio
import logging
import shortuuid
class NotificationController:
def __init__(self, cbpi):
'''
:param cbpi: craftbeerpi object
'''
self.cbpi = cbpi
self.logger = logging.getLogger(__name__)
self.callback_cache = {}
def notify(self, title, message: str, type: str = "info", action=[]) -> None:
'''
This is a convinience method to send notification to the client
:param key: notification key
:param message: notification message
:param type: notification type (info,warning,danger,successs)
:return:
'''
notifcation_id = shortuuid.uuid()
def prepare_action(item):
item.id = shortuuid.uuid()
return item.to_dict()
actions = list(map(lambda item: prepare_action(item), action))
self.callback_cache[notifcation_id] = action
self.cbpi.ws.send(dict(id=notifcation_id, topic="notifiaction", type=type, title=title, message=message, action=actions))
def notify_callback(self, notification_id, action_id) -> None:
try:
action = next((item for item in self.callback_cache[notification_id] if item.id == action_id), None)
if action.method is not None:
asyncio.create_task(action.method())
del self.callback_cache[notification_id]
except Exception as e:
self.logger.error("Faild to call notificatoin callback")

View file

@ -39,7 +39,7 @@ class RecipeController:
path = os.path.join(".", 'config', "recipes", "{}.yaml".format(name)) path = os.path.join(".", 'config', "recipes", "{}.yaml".format(name))
with open(path, "w") as file: with open(path, "w") as file:
yaml.dump(data, file, indent=4, sort_keys=True) yaml.dump(data, file, indent=4, sort_keys=True)
self.cbpi.notify("{} saved".format(data["basic"].get("name")))
async def get_recipes(self): async def get_recipes(self):
path = os.path.join(".", 'config', "recipes") path = os.path.join(".", 'config', "recipes")
@ -65,7 +65,7 @@ class RecipeController:
async def remove(self, name): async def remove(self, name):
path = os.path.join(".", 'config', "recipes", "{}.yaml".format(name)) path = os.path.join(".", 'config', "recipes", "{}.yaml".format(name))
os.remove(path) os.remove(path)
self.cbpi.notify("{} delted".format(name))
async def brew(self, name): async def brew(self, name):

View file

@ -1,4 +1,5 @@
import asyncio import asyncio
import cbpi
import copy import copy
import json import json
import logging import logging
@ -6,7 +7,7 @@ import os.path
from os import listdir from os import listdir
from os.path import isfile, join from os.path import isfile, join
import shortuuid import shortuuid
from cbpi.api.dataclasses import Props, Step from cbpi.api.dataclasses import NotificationAction, Props, Step
from tabulate import tabulate from tabulate import tabulate
from ..api.step import StepMove, StepResult, StepState from ..api.step import StepMove, StepResult, StepState
@ -129,8 +130,7 @@ class StepController:
await self.start_step(step) await self.start_step(step)
await self.save() await self.save()
return return
self.cbpi.notify("Brewing Complete", "Now the yeast will take over",action=[NotificationAction("OK")])
self.cbpi.notify(message="BREWING COMPLETE")
logging.info("BREWING COMPLETE") logging.info("BREWING COMPLETE")
async def previous(self): async def previous(self):

View file

@ -1,4 +1,5 @@
from cbpi.controller.notification_controller import NotificationController
import logging import logging
from os import urandom from os import urandom
import os import os
@ -39,7 +40,9 @@ from cbpi.http_endpoints.http_recipe import RecipeHttpEndpoints
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
from cbpi.http_endpoints.http_system import SystemHttpEndpoints from cbpi.http_endpoints.http_system import SystemHttpEndpoints
from cbpi.http_endpoints.http_log import LogHttpEndpoints from cbpi.http_endpoints.http_log import LogHttpEndpoints
from cbpi.http_endpoints.http_notification import NotificationHttpEndpoints
import shortuuid
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -98,9 +101,9 @@ class CraftBeerPi:
self.kettle = KettleController(self) self.kettle = KettleController(self)
self.step : StepController = StepController(self) self.step : StepController = StepController(self)
self.recipe : RecipeController = RecipeController(self) self.recipe : RecipeController = RecipeController(self)
self.notification : NotificationController = NotificationController(self)
#self.satellite: SatelliteController = SatelliteController(self) #self.satellite: SatelliteController = SatelliteController(self)
self.dashboard = DashboardController(self) self.dashboard = DashboardController(self)
self.http_step = StepHttpEndpoints(self) self.http_step = StepHttpEndpoints(self)
self.http_recipe = RecipeHttpEndpoints(self) self.http_recipe = RecipeHttpEndpoints(self)
self.http_sensor = SensorHttpEndpoints(self) self.http_sensor = SensorHttpEndpoints(self)
@ -111,6 +114,7 @@ class CraftBeerPi:
self.http_plugin = PluginHttpEndpoints(self) self.http_plugin = PluginHttpEndpoints(self)
self.http_system = SystemHttpEndpoints(self) self.http_system = SystemHttpEndpoints(self)
self.http_log = LogHttpEndpoints(self) self.http_log = LogHttpEndpoints(self)
self.http_notification = NotificationHttpEndpoints(self)
self.login = Login(self) self.login = Login(self)
def _setup_shutdownhook(self): def _setup_shutdownhook(self):
@ -208,18 +212,10 @@ class CraftBeerPi:
def notify(self, title: str, message: str, type: str = "info", action=[]) -> None:
self.notification.notify(title, message, type, action)
def notify(self, message: str, type: str = "info") -> None:
'''
This is a convinience method to send notification to the client
:param key: notification key
:param message: notification message
:param type: notification type (info,warning,danger,successs)
:return:
'''
self.ws.send(dict(topic="notifiaction", type=type, message=message))
async def call_initializer(self, app): async def call_initializer(self, app):
self.initializer = sorted(self.initializer, key=lambda k: k['order']) self.initializer = sorted(self.initializer, key=lambda k: k['order'])
for i in self.initializer: for i in self.initializer:

View file

@ -1,21 +1,33 @@
from socket import timeout
from typing import KeysView
from voluptuous.schema_builder import message
from cbpi.api.dataclasses import NotificationAction
import logging import logging
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from datetime import datetime
from cbpi.api import * from cbpi.api import *
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@parameters([]) @parameters([])
class DummyActor(CBPiActor): class DummyActor(CBPiActor):
my_name = ""
# Custom property which can be configured by the user def __init__(self, cbpi, id, props):
@action("test", parameters={}) super().__init__(cbpi, id, props)
async def action1(self, **kwargs):
async def yes(self, **kwargs):
self.my_name = kwargs.get("name") print("YES!")
pass await self.cbpi.step.next()
@action("HELLO WORLD", {})
async def helloWorld(self, **kwargs):
print("HELLO WORLD")
self.cbpi.notify(title="HELLO WORLD", message="DO YOU WANT TO START THE NEXT STEP", action=[NotificationAction("YES", self.yes), NotificationAction("NO")])
async def start(self): async def start(self):
await super().start() await super().start()

View file

@ -30,12 +30,12 @@ class GPIOActor(CBPiActor):
@action(key="Cusotm Action", parameters=[Property.Number("Value", configurable=True), Property.Kettle("Kettle")]) @action(key="Cusotm Action", parameters=[Property.Number("Value", configurable=True), Property.Kettle("Kettle")])
async def custom_action(self, **kwargs): async def custom_action(self, **kwargs):
print("ACTION", kwargs) print("ACTION", kwargs)
self.cbpi.notify("ACTION CALLED")
@action(key="Cusotm Action2", parameters=[Property.Number("Value", configurable=True)]) @action(key="Cusotm Action2", parameters=[Property.Number("Value", configurable=True)])
async def custom_action2(self, **kwargs): async def custom_action2(self, **kwargs):
print("ACTION2") print("ACTION2")
self.cbpi.notify("ACTION CALLED")
def get_GPIO_state(self, state): def get_GPIO_state(self, state):
# ON # ON

View file

@ -21,7 +21,7 @@ class MashStep(CBPiStep):
async def custom_action(self, Value, **kwargs): async def custom_action(self, Value, **kwargs):
self.summary = "VALUE FROM ACTION {}".format(Value) self.summary = "VALUE FROM ACTION {}".format(Value)
await self.push_update() await self.push_update()
self.cbpi.notify("ACTION 2 CALLED".format(Value))
async def on_timer_done(self,timer): async def on_timer_done(self,timer):
self.summary = "" self.summary = ""
@ -60,12 +60,12 @@ class WaitStep(CBPiStep):
@action(key="Custom Step Action", parameters=[]) @action(key="Custom Step Action", parameters=[])
async def hello(self, **kwargs): async def hello(self, **kwargs):
print("ACTION") print("ACTION")
self.cbpi.notify("ACTION 1 CALLED")
@action(key="Custom Step Action 2", parameters=[]) @action(key="Custom Step Action 2", parameters=[])
async def hello2(self, **kwargs): async def hello2(self, **kwargs):
print("ACTION2") print("ACTION2")
self.cbpi.notify("ACTION 2 CALLED")
async def on_timer_done(self,timer): async def on_timer_done(self,timer):
self.summary = "" self.summary = ""
@ -157,7 +157,7 @@ class BoilStep(CBPiStep):
@action("Start Timer", []) @action("Start Timer", [])
async def star_timer(self): async def star_timer(self):
self.cbpi.notify("Timer started")
self.timer.start() self.timer.start()
async def run(self): async def run(self):

View file

@ -0,0 +1,40 @@
from aiohttp import web
from cbpi.api import request_mapping
from cbpi.utils import json_dumps
class NotificationHttpEndpoints:
def __init__(self,cbpi):
self.cbpi = cbpi
self.cbpi.register(self, url_prefix="/notification")
@request_mapping(path="/{id}/action/{action_id}", method="POST", auth_required=False)
async def action(self, request):
"""
---
description: Update an actor
tags:
- Notification
parameters:
- name: "id"
in: "path"
description: "Notification Id"
required: true
type: "string"
- name: "action_id"
in: "path"
description: "Action Id"
required: true
type: "string"
responses:
"200":
description: successful operation
"""
notification_id = request.match_info['id']
action_id = request.match_info['action_id']
print(notification_id, action_id)
self.cbpi.notification.notify_callback(notification_id, action_id)
return web.Response(status=204)