aboutsummaryrefslogtreecommitdiff
path: root/NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py
diff options
context:
space:
mode:
authorJakob Stendahl <14180120+JakobST1n@users.noreply.github.com>2021-10-11 20:02:04 +0200
committerGitHub <noreply@github.com>2021-10-11 20:02:04 +0200
commitc67531161e56488166a33232f87566309ba8676e (patch)
tree846e59a020e80bea48557d5a06af5728e44961ff /NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py
parente6880cd8ccf82d993f222cb14b4860581654acb8 (diff)
parentc1b6eec770b885a9829e1f62bad5cc99389ca429 (diff)
downloadLuxcena-Neo-c67531161e56488166a33232f87566309ba8676e.tar.gz
Luxcena-Neo-c67531161e56488166a33232f87566309ba8676e.zip
Merge pull request #24 from JakobST1n/rebuild
v1.0.0
Diffstat (limited to 'NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py')
-rw-r--r--NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py266
1 files changed, 266 insertions, 0 deletions
diff --git a/NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py b/NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py
new file mode 100644
index 0000000..4da3093
--- /dev/null
+++ b/NeoRuntime/Runtime/luxcena_neo/neo_behaviour.py
@@ -0,0 +1,266 @@
+import json
+from os import path
+from enum import Enum
+from .strip import detect_format_convert_color
+from .color_utils import rgb_from_twentyfour_bit, hex_from_twentyfour_bit
+
+class NeoBehaviour:
+ """
+ This is the base-class "main" should inherit from!
+ All methods are blocking :) This means that you could potentially loose a "tick"
+ For example, if "eachSecond" is taking up the thread, and the clock goes from 11:58 to 12:02, "eachHour", will not be called.
+ """
+
+ def __init__(self, package_path):
+ """
+ THIS METHOD SHOULD NOT BE OVERIDDEN! Use onStart if you want a setup-method!!!
+ Contains basic setup
+ """
+ self.var = Variables(package_path)
+
+ self.declare = self.var.declare
+ self.declare_variables()
+ del self.declare
+
+ def declare_variables(self):
+ """ This should be overridden, and ALL variables should be declared here. """
+ return
+
+ def on_start(self):
+ """ This method will be run right after __init__ """
+ return
+
+ def each_tick(self):
+ """ This method will be run every tick, that means every time the program has time """
+ return
+
+ def each_second(self):
+ """ This method is called every second (on the clock), given that the thread is open """
+ return
+
+ def each_minute(self):
+ """ This method is called every mintue (on the clock), given that the thread is open """
+ return
+
+ def each_hour(self):
+ """ This method is called every whole hour (on the clock), given that the thread is open """
+ return
+
+ def each_day(self):
+ """ This method is called every day at noon, given that the thread is open """
+ return
+
+class VariableType(Enum):
+ TEXT = 1
+ INT = 2
+ FLOAT = 3
+ COLOR = 4
+ BOOL = 5
+
+class Variables:
+
+ def __init__(self, package_path):
+ self.__vars = {}
+ self.__vars_save_file = "{}/state.json".format(package_path)
+ self.__saved_variables = {}
+ self.read_saved_variables()
+
+ def __getattr__(self, name):
+ if name in ["_Variables__vars", "_Variables__vars_save_file", "_Variables__saved_variables"]:
+ return super(Variables, self).__getattr__(name)
+ return self.__vars[name].value
+
+ def __setattr__(self, name, value):
+ if name in ["_Variables__vars", "_Variables__vars_save_file", "_Variables__saved_variables"]:
+ super(Variables, self).__setattr__(name, value)
+ else:
+ self.__vars[name].value = value
+
+ def __delattr__(self, name):
+ if name in ["_Variables__vars", "_Variables__vars_save_file", "_Variables__saved_variables"]:
+ super(Variables, self).__delattr__(name)
+ else:
+ del self.__vars[name]
+
+ def __getitem__(self, name):
+ return self.__vars[name]
+
+ def __setitem__(self, name, value):
+ self.__vars[name].value = value
+
+ def __contains__(self, name):
+ return name in self.__vars
+
+ def __repr__(self):
+ return json.dumps({name: var.value for name, var in self.__vars.items()})
+
+ def __str__(self):
+ return repr(self)
+
+ def __dir__(self):
+ return super(Variables, self).__dir__() + [name for name in self.__vars.keys()]
+
+ def __len__(self):
+ return len(self.__vars)
+
+ def __iter__(self):
+ return iter(self.__vars.items())
+
+ def declare(self, variable):
+ """ Declare a new variable. """
+ if variable.name in self.__vars:
+ raise Exception("Variable with name {} already defined.".format(variable.name))
+ if variable.name in self.__saved_variables:
+ variable.value = self.__saved_variables[variable.name]
+
+ variable.set_save_func(self.save_variables)
+ self.__vars[variable.name] = variable
+
+ def read_saved_variables(self):
+ """ Read saved variable values from file. """
+ if not path.exists(self.__vars_save_file): return
+ try:
+ with open(self.__vars_save_file, "r") as f:
+ self.__saved_variables = json.load(f)
+ except:
+ print("Could not load saved variables")
+
+ def save_variables(self):
+ """ Save variable values to file. """
+ self.__saved_variables = {name: var.value for name, var in self.__vars.items()}
+ with open(self.__vars_save_file, "w") as f:
+ f.write(json.dumps(self.__saved_variables))
+
+ def to_dict(self):
+ return {x.name: x.to_dict() for x in self.__vars.values()}
+
+class Variable:
+
+ def __init__(self, name, default, var_type: VariableType, on_change = None):
+ self.__name = name
+ self.__value = default
+ self.__var_type = var_type
+ self.__on_change = on_change
+ self.__save_func = None
+
+ @property
+ def name(self): return self.__name
+
+ @property
+ def value(self): return self.__value
+
+ @value.setter
+ def value(self, value):
+ self.__value = value
+ if self.__save_func is not None:
+ self.__save_func()
+ if self.__on_change is not None:
+ self.__on_change(self.value)
+
+ @property
+ def var_type(self): return self.__var_type.name
+
+ def to_dict(self):
+ return {"name": self.name, "value": self.value, "type": self.var_type}
+
+ def __str__(self):
+ return "{}: {}".format(self.name, self.value)
+
+ def set_save_func(self, save_func):
+ self.__save_func = save_func
+
+class ColorVariable(Variable):
+
+ def __init__(self, name: str, *color, **kwargs):
+ if not self.verify_color(*color):
+ raise Exception("Invalid color {}".format(color))
+ super().__init__(name, self.extract_interesting(*color), VariableType.COLOR, **kwargs)
+
+ @Variable.value.setter
+ def value(self, *color):
+ if not self.verify_color(*color):
+ print("Attempting to set {} to invalid value {}".format(self.name, color))
+ return
+ super(ColorVariable, type(self)).value.fset(self, self.extract_interesting(*color))
+
+ def verify_color(self, *color):
+ if (len(color) == 1) and (isinstance(color[0], str)):
+ return True
+ if (len(color) == 1) and (isinstance(color[0], tuple)):
+ if len(color[0]) != 3: return False
+ for c in color[0]:
+ if not (0 <= c <= 255): return False
+ return True
+ if (len(color) == 1) and (isinstance(color[0], int)):
+ return True
+ if (len(color) == 3):
+ for c in color:
+ if not isinstance(c, int): return False
+ if not (0 <= c <= 255): return False
+ return True
+ return False
+
+ def extract_interesting(self, *color):
+ if (len(color) == 1): return color[0]
+ return color
+
+class IntegerVariable(Variable):
+
+ def __init__(self, name: str, default: int = 0, min_val: int = 0, max_val: int = 255, **kwargs):
+ self.__min = min_val
+ self.__max = max_val
+ super().__init__(name, default, VariableType.INT)
+
+ @Variable.value.setter
+ def value(self, value):
+ try:
+ value = int(value)
+ if (self.__min <= value <= self.__max):
+ super(IntegerVariable, type(self)).value.fset(self, value)
+ else:
+ print("Attempted to set {} to {} but range is [{},{}].".format(self.name, value, self.__min, self.__max))
+ except ValueError:
+ print("Attempted to set {} to \"{}\", which is not a valid integer...".format(self.name, value))
+
+ def to_dict(self):
+ return {"name": self.name, "value": self.value, "type": self.var_type, "min": self.__min, "max": self.__max}
+
+
+class FloatVariable(Variable):
+
+ def __init__(self, name: str, default: float = 0.0, min_val: float = 0.0, max_val: float = 255.0, **kwargs):
+ self.__min = min_val
+ self.__max = max_val
+ super().__init__(name, default, VariableType.FLOAT)
+
+ @Variable.value.setter
+ def value(self, value):
+ try:
+ value = float(value)
+ if (self.__min <= value <= self.__max):
+ super(FloatVariable, type(self)).value.fset(self, value)
+ else:
+ print("Attempted to set {} to {} but range is [{},{}].".format(self.name, value, self.__min, self.__max))
+ except ValueError:
+ print("Attempted to set {} to \"{}\", which is not a valid float...".format(self.name, self.value))
+
+ def __str__(self):
+ return round(self.value, 2)
+
+ def to_dict(self):
+ return {"name": self.name, "value": self.value, "type": self.var_type, "min": self.__min, "max": self.__max}
+
+
+
+class BooleanVariable(Variable):
+
+ def __init__(self, name: str, default: bool, **kwargs):
+ super().__init__(name, default, VariableType.BOOL)
+
+ @Variable.value.setter
+ def value(self, value):
+ try:
+ value = bool(value)
+ super(BooleanVariable, type(self)).value.fset(self, value)
+ except:
+ print("Attempted to set {} to \"{}\", which is not a valid bool...".format(self.name, value))