From 8a5822e403e64dbae1d7684631b695b93b215368 Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Mon, 25 Oct 2021 10:21:14 +0200 Subject: [PATCH] Implement Counter and Date plugins in util.py. --- controlpi_plugins/util.py | 159 +++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/controlpi_plugins/util.py b/controlpi_plugins/util.py index 278fc3a..d8b63a8 100644 --- a/controlpi_plugins/util.py +++ b/controlpi_plugins/util.py @@ -38,6 +38,7 @@ Test Log: {'sender': 'Test Alias', 'id': 'translated', 'content': 'Test Message'} """ import asyncio +import datetime from controlpi import BasePlugin, Message, MessageTemplate @@ -367,7 +368,7 @@ class Alias(BasePlugin): Optional configuration keys: - - 'to': translated message to be sent. + - 'to': translated message(s) to be sent. - 'translate': array of pairs of keys to be translated. """ @@ -407,3 +408,159 @@ class Alias(BasePlugin): async def run(self) -> None: """Run no code proactively.""" pass + + +class Counter(BasePlugin): + """Count messages confirming to a given template. + + The plugin counts messages confirming to the given template. The + counter can be queried and reset by commands. The 'reset' command also + queries the last count before the reset: + >>> import controlpi + >>> asyncio.run(controlpi.test( + ... {"Test Counter": {"plugin": "Counter", + ... "count": {"id": {"const": 42}}}}, + ... [{"target": "Test Counter", "command": "get count"}, + ... {"id": 42}, {"id": 42}, {"id": 49}, + ... {"target": "Test Counter", "command": "get count"}, + ... {"id": 42}, {"id": 42}, {"id": 42}, + ... {"target": "Test Counter", "command": "reset"}, + ... {"target": "Test Counter", "command": "get count"}, + ... {"id": 42}, {"id": 42}, {"id": 42}, + ... {"target": "Test Counter", "command": "get count"}])) + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + test(): {'sender': '', 'event': 'registered', + 'client': 'Test Counter', 'plugin': 'Counter', + 'sends': [{'count': {'type': 'integer'}}], + 'receives': [{'id': {'const': 42}}, + {'target': {'const': 'Test Counter'}, + 'command': {'const': 'get count'}}, + {'target': {'const': 'Test Counter'}, + 'command': {'const': 'reset'}}]} + test(): {'sender': 'test()', 'target': 'Test Counter', + 'command': 'get count'} + test(): {'sender': 'Test Counter', 'count': 0} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 49} + test(): {'sender': 'test()', 'target': 'Test Counter', + 'command': 'get count'} + test(): {'sender': 'Test Counter', 'count': 2} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'target': 'Test Counter', + 'command': 'reset'} + test(): {'sender': 'Test Counter', 'count': 5} + test(): {'sender': 'test()', 'target': 'Test Counter', + 'command': 'get count'} + test(): {'sender': 'Test Counter', 'count': 0} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'id': 42} + test(): {'sender': 'test()', 'target': 'Test Counter', + 'command': 'get count'} + test(): {'sender': 'Test Counter', 'count': 3} + """ + + CONF_SCHEMA = {'properties': {'count': {'type': 'object'}}, + 'required': ['count']} + """Schema for Counter plugin configuration. + + Required configuration key: + + - 'count': template of messages to be counted. + """ + + def process_conf(self) -> None: + """Register plugin as bus client.""" + self._count = 0 + self._template = MessageTemplate(self.conf['count']) + sends = [MessageTemplate({'count': {'type': 'integer'}})] + receives = [self._template, + MessageTemplate({'target': {'const': self.name}, + 'command': {'const': 'get count'}}), + MessageTemplate({'target': {'const': self.name}, + 'command': {'const': 'reset'}})] + self.bus.register(self.name, 'Counter', sends, receives, self.receive) + + async def receive(self, message: Message) -> None: + """Send current date and time as message.""" + if self._template.check(message): + self._count += 1 + if ('target' in message and message['target'] == self.name and + 'command' in message): + if message['command'] == 'get count': + await self.bus.send(Message(self.name, {'count': self._count})) + elif message['command'] == 'reset': + count = self._count + self._count = 0 + await self.bus.send(Message(self.name, {'count': count})) + + async def run(self) -> None: + """Run no code proactively.""" + pass + + +class Date(BasePlugin): + """Send message with current date. + + The plugin reacts to 'get date' commands by sending messages with + a 'date' key: + >>> import controlpi + >>> asyncio.run(controlpi.test( + ... {"Test Date": {"plugin": "Date"}}, + ... [{"target": "Test Date", "command": "get date"}])) + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + test(): {'sender': '', 'event': 'registered', + 'client': 'Test Date', 'plugin': 'Date', + 'sends': [{'date': {'type': 'string'}}], + 'receives': [{'target': {'const': 'Test Date'}, + 'command': {'const': 'get date'}}]} + test(): {'sender': 'test()', 'target': 'Test Date', + 'command': 'get date'} + test(): {'sender': 'Test Date', 'date': ...} + + The format of the date can be configured with the 'format' + configuration key: + >>> asyncio.run(controlpi.test( + ... {"Test Date": {"plugin": "Date", + ... "format": "%Y%m%d%H%M%S%f"}}, + ... [{"target": "Test Date", "command": "get date"}])) + ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS + test(): {'sender': '', 'event': 'registered', + 'client': 'Test Date', 'plugin': 'Date', + 'sends': [{'date': {'type': 'string'}}], + 'receives': [{'target': {'const': 'Test Date'}, + 'command': {'const': 'get date'}}]} + test(): {'sender': 'test()', 'target': 'Test Date', + 'command': 'get date'} + test(): {'sender': 'Test Date', 'date': ...} + """ + + CONF_SCHEMA = {'properties': {'format': + {'type': 'string', + 'default': '%Y-%m-%d %H:%M:%S'}}} + """Schema for Date plugin configuration. + + Optional configuration key: + + - 'format': format for the sent datetime string. + Default: '%Y-%m-%d %H:%M:%S' + """ + + def process_conf(self) -> None: + """Register plugin as bus client.""" + sends = [MessageTemplate({'date': {'type': 'string'}})] + receives = [MessageTemplate({'target': {'const': self.name}, + 'command': {'const': 'get date'}})] + self.bus.register(self.name, 'Date', sends, receives, self.date) + + async def date(self, message: Message) -> None: + """Send current date and time as message.""" + date = datetime.datetime.now().strftime(self.conf['format']) + await self.bus.send(Message(self.name, {'date': date})) + + async def run(self) -> None: + """Run no code proactively.""" + pass -- 2.34.1