2021-01-22 23:25:20 +01:00
|
|
|
|
|
|
|
import logging
|
|
|
|
import os.path
|
|
|
|
import json
|
|
|
|
import sys, os
|
|
|
|
import shortuuid
|
|
|
|
import asyncio
|
|
|
|
|
|
|
|
from tabulate import tabulate
|
|
|
|
|
|
|
|
class BasicController:
|
|
|
|
|
|
|
|
def __init__(self, cbpi, file):
|
2021-01-24 22:14:57 +01:00
|
|
|
self.update_key = ""
|
2021-01-22 23:25:20 +01:00
|
|
|
self.name = self.__class__.__name__
|
|
|
|
self.cbpi = cbpi
|
|
|
|
self.cbpi.register(self)
|
|
|
|
self.service = self
|
|
|
|
self.types = {}
|
|
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
self.data = []
|
|
|
|
self.autostart = True
|
|
|
|
self._loop = asyncio.get_event_loop()
|
|
|
|
self.path = os.path.join(".", 'config', file)
|
|
|
|
self.cbpi.app.on_cleanup.append(self.shutdown)
|
|
|
|
|
|
|
|
async def init(self):
|
|
|
|
await self.load()
|
|
|
|
|
|
|
|
async def load(self):
|
|
|
|
logging.info("{} Load ".format(self.name))
|
|
|
|
with open(self.path) as json_file:
|
|
|
|
data = json.load(json_file)
|
|
|
|
|
|
|
|
self.data = data["data"]
|
|
|
|
|
|
|
|
if self.autostart is True:
|
|
|
|
for d in self.data:
|
|
|
|
logging.info("{} Starting ".format(self.name))
|
|
|
|
await self.start(d.get("id"))
|
|
|
|
|
|
|
|
async def save(self):
|
|
|
|
logging.info("{} Save ".format(self.name))
|
|
|
|
data = dict(data=list(map(lambda x: self.create_dict(x), self.data)))
|
|
|
|
with open(self.path, "w") as file:
|
|
|
|
json.dump(data, file, indent=4, sort_keys=True)
|
|
|
|
await self.push_udpate()
|
|
|
|
|
|
|
|
async def push_udpate(self):
|
2021-01-24 22:14:57 +01:00
|
|
|
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda x: self.create_dict(x), self.data))))
|
2021-01-22 23:25:20 +01:00
|
|
|
|
|
|
|
def create_dict(self, data):
|
|
|
|
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), status=data.get("status"),props=data.get("props", []))
|
|
|
|
|
|
|
|
def find_by_id(self, id):
|
|
|
|
return next((item for item in self.data if item["id"] == id), None)
|
|
|
|
|
|
|
|
def get_index_by_id(self, id):
|
|
|
|
return next((i for i, item in enumerate(self.data) if item["id"] == id), None)
|
|
|
|
|
|
|
|
async def shutdown(self, app):
|
|
|
|
logging.info("{} Shutdown ".format(self.name))
|
|
|
|
tasks = []
|
|
|
|
for item in self.data:
|
|
|
|
if item.get("instance") is not None and item.get("instance").running is True:
|
|
|
|
await item.get("instance").stop()
|
|
|
|
tasks.append(item.get("instance").task)
|
|
|
|
await asyncio.gather(*tasks)
|
|
|
|
await self.save()
|
|
|
|
|
|
|
|
async def stop(self, id):
|
|
|
|
logging.info("{} Stop Id {} ".format(self.name, id))
|
|
|
|
|
|
|
|
try:
|
|
|
|
item = self.find_by_id(id)
|
|
|
|
instance = item.get("instance")
|
|
|
|
await instance.stop()
|
|
|
|
await instance.task
|
|
|
|
except Exception as e:
|
|
|
|
logging.error("{} Cant stop {} - {}".format(self.name, id, e))
|
|
|
|
|
|
|
|
async def start(self, id):
|
|
|
|
logging.info("{} Start Id {} ".format(self.name, id))
|
|
|
|
try:
|
|
|
|
item = self.find_by_id(id)
|
|
|
|
instance = item.get("instance")
|
|
|
|
|
|
|
|
if instance is not None and instance.running is True:
|
|
|
|
logging.warning("{} already running {}".format(self.name, id))
|
|
|
|
return
|
|
|
|
|
|
|
|
type = item["type"]
|
|
|
|
print(type)
|
|
|
|
print(self.types)
|
|
|
|
clazz = self.types[type]["class"]
|
|
|
|
item["instance"] = clazz(self.cbpi, item["id"], {})
|
|
|
|
print(item["instance"])
|
|
|
|
await item["instance"].start()
|
|
|
|
item["instance"].task = self._loop.create_task(item["instance"].run())
|
|
|
|
logging.info("Sensor started {}".format(id))
|
|
|
|
except Exception as e:
|
|
|
|
logging.error("{} Cant start {} - {}".format(self.name, id, e))
|
|
|
|
|
|
|
|
def get_types(self):
|
|
|
|
logging.info("{} Get Types".format(self.name))
|
|
|
|
result = {}
|
|
|
|
for key, value in self.types.items():
|
|
|
|
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
|
|
|
|
return result
|
|
|
|
|
|
|
|
def get_state(self):
|
|
|
|
logging.info("{} Get State".format(self.name))
|
|
|
|
return {"data": list(map(lambda x: self.create_dict(x), self.data)), "types":self.get_types()}
|
|
|
|
|
|
|
|
async def add(self, data):
|
|
|
|
logging.info("{} Add".format(self.name))
|
|
|
|
id = shortuuid.uuid()
|
|
|
|
item = {**data, "id": id, "instance": None , "name": data.get("name"), "props": data.get("props", {})}
|
|
|
|
self.data.append(item)
|
|
|
|
if self.autostart is True:
|
|
|
|
await self.start(id)
|
|
|
|
await self.save()
|
|
|
|
return item
|
|
|
|
|
|
|
|
async def update(self, id, data) -> dict:
|
|
|
|
logging.info("{} Get Update".format(self.name))
|
|
|
|
await self.stop(id)
|
|
|
|
if self.autostart is True:
|
|
|
|
await self.start(id)
|
|
|
|
self.data = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.data))
|
|
|
|
await self.save()
|
|
|
|
return self.find_by_id(id)
|
|
|
|
|
|
|
|
async def delete(self, id) -> None:
|
|
|
|
logging.info("{} Delete".format(self.name))
|
|
|
|
await self.stop(id)
|
|
|
|
self.data = list(filter(lambda x: x["id"] != id, self.data))
|
|
|
|
await self.save()
|
|
|
|
|
|
|
|
async def call_action(self, id, action, parameter) -> None:
|
|
|
|
|
|
|
|
logging.info("{} call all Action {} {}".format(self.name, id, action))
|
|
|
|
try:
|
|
|
|
item = self.find_by_id(id)
|
|
|
|
print(item)
|
|
|
|
instance = item.get("instance")
|
|
|
|
await instance.__getattribute__(action)(**parameter)
|
|
|
|
except Exception as e:
|
|
|
|
logging.error("{} Faild to call action on {} {} {}".format(self.name, id, action, e))
|