diff --git a/scada_system/controls/device.py b/scada_system/controls/device.py index 312c8ec..fc645ef 100644 --- a/scada_system/controls/device.py +++ b/scada_system/controls/device.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from typing import Optional, Collection, Any -from abc import ABCMeta, abstractmethod +from abc import ABC, abstractmethod from enum import Enum class DeviceLifecycleState(Enum): @@ -36,7 +36,7 @@ class ActionDescriptor: info: Optional[str] = None -class Device(metaclass=ABCMeta): +class Device(ABC): _state = DeviceLifecycleState.INIT @property diff --git a/scada_system/equipment/turtle_device.py b/scada_system/equipment/turtle_device.py index fc960d0..2758484 100644 --- a/scada_system/equipment/turtle_device.py +++ b/scada_system/equipment/turtle_device.py @@ -1,38 +1,52 @@ -import turtle +from turtle import Turtle from typing import Optional, Collection, Any from controls.device import SynchronyDevice -import time +from controls.device import TraitDescriptor +from controls.device import ActionDescriptor import inspect class TurtleDevice(SynchronyDevice): def open(self): + self.turtle = Turtle() super().open() - turtle.Turtle() def close(self): + self.turtle.clear() super().close() - turtle.bye() def execute(self, action_name: str, *args, **kwargs): - getattr(turtle, action_name)(args[0], *kwargs) + getattr(self.turtle, action_name)(*args, **kwargs) def read(self, trait_name: str): - pass + """Read physical state of trait `trait_name` from device.""" + trait = self.trait_descriptors()[trait_name] + if not trait.readable : super().read(trait_name) + return trait.info def write(self, trait_name: str, value: Any) -> bool: - pass + """Pass `value` to trait `trait_name` of device.""" + if not self.trait_descriptors()[trait_name] : super().write(trait_name, value) + setattr(self.turtle, trait_name, value) def invalidate(self, trait_name: str): + """Invalidate logical state of trait `trait_name`""" pass def trait_descriptors(self): - traits = [attr for attr in turtle.Turtle.__dict__ - if attr.startswith('__') and not attr.startswith('_')] + traits = dict() + for name, value in inspect.getmembers(self.turtle): + if not callable(value) and not name.startswith('_'): + info = f"{value}" + traits[name] = TraitDescriptor(name, info) return traits def action_descriptors(self): - actions = [(name, func.__doc__) for name, func in inspect.getmembers(turtle.Turtle) - if callable(func) and not name.startswith('__') and not name.startswith('_')] + actions = dict() + for name, func in inspect.getmembers(self.turtle): + if callable(func) and not name.startswith('_'): + args = dict(inspect.signature(func).parameters) + info = inspect.getdoc(func) + actions[name] = ActionDescriptor(name, args, info) return actions def __getitem__(self, trait_name: str):