Dmitry Telenkov há 1 ano atrás
pai
commit
8988fdaf8b

+ 8 - 0
codewars.code-workspace

@@ -0,0 +1,8 @@
+{
+	"folders": [
+		{
+			"path": "."
+		}
+	],
+	"settings": {}
+}

+ 123 - 12
courses/python_for_begginers/dec.py

@@ -1,18 +1,129 @@
-def my_decorator(function_to_decorate):
-	def the_wrapper_around_the_original_function():
-		print("Этот код работает до вызова функции")
-		function_to_decorate()
-		print("Этот код работает после вызова функции")
-	return the_wrapper_around_the_original_function
+# -*- coding: utf-8 -*-
 
 
+# def my_decorator(function_to_decorate):
+# 	def the_wrapper_around_the_original_function():
+# 		print("Этот код работает до вызова функции")
+# 		function_to_decorate()
+# 		print("Этот код работает после вызова функции")
+# 	return the_wrapper_around_the_original_function
 
 
-def stand_alone_function():
-	print("Эта функция не изменяется")
 
 
+# def stand_alone_function():
+# 	print("Эта функция не изменяется")
 
 
-@my_decorator
-def another_stand_alone_function():
-	print("Оставль меня в покое")
 
 
+# @my_decorator
+# def another_stand_alone_function():
+# 	print("Оставль меня в покое")
 
 
-another_stand_alone_function()
+
+# another_stand_alone_function()
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Передача аргументов в декорируемую функцию
+
+def a_decorator_passing_argument(function_to_decorate):
+	def a_wrapper_accepting_arguments(arg1, arg2):
+		print "Смотри, что я получил:", arg1, arg2
+		function_to_decorate(arg1, arg2)
+	return a_wrapper_accepting_arguments
+
+
+@a_decorator_passing_argument
+def print_full_name(first_name, last_name):
+	print "Меня зовут", first_name, last_name
+
+# print_full_name("Питер", "Венкман")
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Декорирование методов 
+
+def method_friendly_decorator(method_to_decorate):
+	def wrapper(self, lie):
+		return method_to_decorate(self, lie)
+	return wrapper
+
+
+class Lucy(object):
+
+	def __init__(self): 
+		self.age = 21
+
+	@method_friendly_decorator
+	def sayYourAge(self, lie):
+		print 'Мне %s, а ты бы сколько дал?' % (self.age + lie)
+
+
+# l = Lucy()
+# l.sayYourAge(-3)
+	
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+def a_decorator_passing_arbitrary_arguments(function_to_decorate):
+	def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
+		print "Передали ли мне что-нибудь?:"
+		print args
+		print kwargs
+		function_to_decorate(*args, **kwargs)
+	return a_wrapper_accepting_arbitrary_arguments
+
+@a_decorator_passing_arbitrary_arguments
+def function_with_no_argument():
+	print "No argument here"
+
+# function_with_no_argument()
+
+@a_decorator_passing_arbitrary_arguments
+def function_with_arguments(a, b, c):
+    print a, b, c
+
+# function_with_arguments(1, 2, 3)
+
+@a_decorator_passing_arbitrary_arguments
+def function_with_named_arguments(a, b, c, platypus="Почему нет?"):
+	print "Любят ли %s, %s и %s утконосов? %s" % (a, b, c, platypus)
+
+
+# function_with_named_arguments("Билл", "Линус", "Стив", platypus="Определенно!")
+
+
+class Mary(object):
+
+	def __init__(self):
+		self.age = 31
+
+	@a_decorator_passing_arbitrary_arguments
+	def sayYourAge(self, lie=-3):
+		print 'Мне %s, а ты бы сколько дал?' % (self.age + lie)
+
+
+# m = Mary()
+# m.sayYourAge()
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
+	print "Я создаю декораторы! И я получил следующие аргументы:", decorator_arg1, decorator_arg2
+	def my_decorator(func):
+		print "Я - декоратор. И ты все же смог передать мне эти аргументы:", decorator_arg1, decorator_arg2
+		def wrapped(function_arg1, function_arg2):
+			print ("Я - обёртка вокруг декорируемой функции.\n"
+                  "И я имею доступ ко всем аргументам: \n"
+                  "\t- и декоратора: {0} {1}\n"
+                  "\t- и функции: {2} {3}\n"
+                  "Теперь я могу передать нужные аргументы дальше"
+                  .format(decorator_arg1, decorator_arg2, function_arg1, function_arg2))
+			return func(function_arg1, function_arg2)
+		
+		return wrapped
+	
+	return my_decorator
+
+
+@decorator_maker_with_arguments("Леонард", "Шелдон")
+def decorated_function_with_arguments(function_arg1, function_arg2):
+    print ("Я - декорируемая функция и я знаю только о своих аргументах: {0}"
+           " {1}".format(function_arg1, function_arg2))
+ 
+ 
+decorated_function_with_arguments("Раджеш", "Говард")

+ 20 - 8
courses/python_for_begginers/pytwo.py

@@ -18,17 +18,29 @@ def fooo(*args, **kwargs):
 
 
 
 
 
 
-new_my_class = MyClass
-new_my_class.print_string()
+# new_my_class = MyClass
+# new_my_class.print_string()
+# foo().print_string()
+# MyClass = fooo
+# new_foo = MyClass
+# print(new_foo)
+
+# new_my_class = MyClass()
+# new_my_class.print_string()
 
 
-foo().print_string()
+# def my_decorator(dec_str):
+# 	def wrapper(func):
+# 		# print dec_str
+# 		print "before my func"
+# 		func()
+# 		print "after my_func"
+# 	return wrapper
 
 
-MyClass = fooo
 
 
-new_foo = MyClass
-print(new_foo)
+# @my_decorator("to decorator")
+# def foo():
+# 	print "my_function"
 
 
-# new_my_class = MyClass()
-# new_my_class.print_string()
 
 
+# foo()
 
 

+ 515 - 0
courses/python_for_begginers/sensorman.py

@@ -0,0 +1,515 @@
+'''
+Created on Nov 28, 2012
+
+@author: Repnikov Dmitry
+'''
+
+import os, logging, threading, re, copy
+from jsonrpc_server import JSONRPCServer
+from module_loader import ModuleLoader
+from helperBTE import HelperBTE
+from helperIPcamera import HelperIPcamera
+from message_queue import MessageQueue
+from helperSNMPSensors import HelperSNMPSensors
+from helperElectricityMeter import HelperElectricityMeter
+from helperDGS import HelperDGS
+from helperMPSU import HelperMPSU
+from helperInverPack import HelperInverPackMeter
+from helperCRS import HelperCRS
+from helperPulsar import HelperPulsar
+from helperUPKB import HelperUPKB
+from configman import make_copy
+from sensor_scheduler import SensorScheduler
+
+
+class SensorHolder:
+    """ Class to hold sensor, cache and other """
+    
+    sensors_lock = threading.Lock() # Global lock for sensors
+    def __init__(self, _sensor):
+        self.state = None    # Current state of this sensor
+        self.value = None    # Current value of this sensor
+        self.sensor = _sensor
+    
+    def onChange(self):
+        pass
+
+class SensorManager(JSONRPCServer, HelperPulsar, HelperBTE, HelperIPcamera, HelperSNMPSensors, HelperElectricityMeter, HelperDGS, HelperMPSU, HelperInverPackMeter, HelperCRS, HelperUPKB):
+    """ Sensor manager. API for sensors storing and management. """
+
+    JSONRPC_SERVER_ADDRESS = ("127.0.0.1", 4665)
+    STATE_CHANGE_TRIGGER_PATH = ["notifications", "notifications", "3db09436-17a8-4b0e-b70c-93ceaf094cff", "trigger"]
+    SENSOR_SCHEDULERS = ["DEFAULT", "1W", "CONMAN"]
+    
+    def __init__(self, _configman, _queue_event, _queue_action):
+        self.logger = logging.getLogger(__name__)
+        self.sensors = {}
+        self.sensor_modules = ModuleLoader(__file__, "/../sensors/", "sensor_*", _recursive = True)
+        self.event_modules = ModuleLoader(__file__, "/../events/", "event_*")
+        self.configman = _configman
+        self.queue_event = _queue_event
+        self.queue_action = _queue_action
+        self.deviceman = None
+        self.sensor_schedulers = {}
+        for name in self.SENSOR_SCHEDULERS:
+            self.sensor_schedulers[name] = SensorScheduler(name)
+        
+        HelperBTE.__init__(self, _configman)
+        HelperIPcamera.__init__(self, _configman)
+        HelperSNMPSensors.__init__(self, _configman)
+        HelperElectricityMeter.__init__(self, _configman)
+        HelperDGS.__init__(self, _configman)
+        HelperMPSU.__init__(self, _configman)
+        HelperInverPackMeter.__init__(self, _configman)
+        HelperCRS.__init__(self, _configman)
+        HelperPulsar.__init__(self, _configman)
+        HelperUPKB.__init__(self, _configman)
+        
+        JSONRPCServer.__init__(self)
+    
+    def set_device_man(self, _deviceman):
+        self.deviceman = _deviceman
+        try:
+            HelperBTE.set_device_man(_deviceman)
+            HelperDGS.set_device_man(_deviceman)
+            HelperMPSU.set_device_man(_deviceman)
+            HelperPulsar.set_device_man(_deviceman)
+        except: self.logger.exception("Unable to set device manager instance")
+        #try: self.MPSU_check({"alias":"serial232.0", "name":"/dev/ttyS1"}, 9600)
+        #except: self.logger.exception("Unable to set check MPSU")
+    
+    def start_sensor(self, id):
+        """ Start sensor thread, if any """
+        try:
+            self.logger.debug("Starting sensor module '"+id+"'")
+            self.put_value_pair(id, (None, None), default=True)
+            self.sensors[id].sensor.restart()
+        except: self.logger.exception("Unable to start sensor '"+id+"'")
+    
+    def start_scheduler(self):
+        try:
+            for scheduler in self.sensor_schedulers.values():
+                scheduler.start()
+        except:
+            self.logger.exception("start scheduler error")
+    
+    def register_polling_sensor(self, sensor):
+        self.sensor_schedulers[sensor.get_scheduler_name()].register_sensor(sensor)
+        
+    def unregister_polling_sensor(self, sensor):
+        self.sensor_schedulers[sensor.get_scheduler_name()].unregister_sensor(sensor)
+    
+    def list_sensor_ids(self):
+        return self.sensors.keys()
+    
+    def find_sensor_by_class(self, class_name):
+        """ Find sensor id by class name (can be regular expression) """
+        SensorHolder.sensors_lock.acquire()
+        res = []
+        try:
+            for id in self.sensors.keys():
+                if re.match(class_name, self.sensors[id].sensor.__class__.__name__):
+                    res.append(id)
+        except: self.logger.exception("Unable to find sensor by class '"+str(class_name)+"'")
+        SensorHolder.sensors_lock.release()
+        return res
+    
+    def find_sensor_by_group(self, group_name):
+        """ Find sensor id by group name (can be regular expression) """
+        SensorHolder.sensors_lock.acquire()
+        res = []
+        try:
+            for id in self.sensors.keys():
+                if re.match(group_name, self.sensors[id].sensor.group):
+                    res.append(id)
+        except: self.logger.exception("Unable to find sensor by group '"+str(group_name)+"'")
+        SensorHolder.sensors_lock.release()
+        return res
+    
+    def get_available_classes(self):
+        """ Return dictionary {"class_name":("description", [ids])} """
+        res = {}
+        self.logger.debug("get_available_classes start")
+        SensorHolder.sensors_lock.acquire()
+        try:
+            sensor_classes = self.sensor_modules.class_by_regexp("Sensor[\w]+")
+            for sensor_class in sensor_classes: 
+                sensor_ids = []
+                for id in self.sensors.keys():
+                    if (not (id in sensor_ids)) and (self.sensors[id].sensor.__class__.__name__ == sensor_class.__name__):
+                        sensor_ids.append(id)
+                res[sensor_class.__name__] = ( [sensor_class.__doc__, sensor_ids] )
+        except: res = None
+        SensorHolder.sensors_lock.release()
+        self.logger.debug("get_available_classes end")
+        return res
+    
+    def get_view_dict(self, id):
+        """
+        Returns view dictionary of sensor. This dictionary
+        contains strings, that can be used in formatting.
+        """
+        try:
+            return self.sensors[id].sensor.get_view_dict()
+        except:
+            return {}
+    
+    def get_view_dicts(self, ids):
+        """ Returns view dictionaries of sensors. """
+        res = {}
+        try:
+            for id in ids: res[id] = self.get_view_dict(id)
+            return res
+        except: return {}
+    
+    def get_view_dict_by_alias(self, alias):
+        try:    return self.get_sensor_by_alias(alias).get_view_dict()
+        except: return {}
+    
+    def get_view_dicts_by_aliases(self, aliases):
+        res = {}
+        for alias in aliases:
+            try: res[alias] = self.get_sensor_by_alias(alias).get_view_dict()
+            except:	self.logger.exception("get_sensor_by_alias exception")
+        return res
+    
+    def get_all_sensors_views(self):
+        res = {}
+        for id in self.sensors.keys():
+            res[id] = self.get_view_dict(id)
+        return res
+    
+    def get_value_description(self, id, value):
+        """ Returns full form of value description, include state """
+        try:    return self.sensors[id].sensor.get_value_descr(value)
+        except: return {}
+    
+    def apply_view_dict(self, id, nview):
+        """ Set dict nview to sensor (through SensorView class) """
+        try: return self.sensors[id].sensor.apply_view_dict(nview)
+        except: return False
+        
+    def apply_view_dict_by_alias(self, alias, nview):
+        """ Set dict nview to sensor (through SensorView class) """
+        try: return self.get_sensor_by_alias(alias).apply_view_dict(nview)
+        except: return False
+    
+    def put_value_pair(self, id, pair, default = False, priority = None):
+        """ Write value pair (value, state) to sensor corresponding files """
+        """ default - if no value/state files were created, this pair be written as default """
+        value, state = pair
+        fRefreshValue, fRefreshSate = False, False
+        
+        
+        SensorHolder.sensors_lock.acquire()
+        if not (id in self.sensors.keys()):
+            SensorHolder.sensors_lock.release()
+            return
+        
+        try:
+            if not default: old_value, old_state = self.get_value_pair(id, False)
+            else: old_value, old_state = pair
+        except:
+            self.logger.exception("Exception while put state/value for sensor '"+str(id)+"'")
+            SensorHolder.sensors_lock.release()
+            return
+        
+        try:
+            if (old_value != value) or (default): fRefreshValue, self.sensors[id].value = True, value
+            if (old_state != state) or (default): fRefreshSate,  self.sensors[id].state = True, state
+        except:
+            self.logger.exception("Exception while put state/value for sensor '"+str(id)+"'")
+            SensorHolder.sensors_lock.release()
+            return
+        
+        #fRefreshValue = fRefreshValue or self.sensors[id].sensor.history['any_value']
+        fRefreshValue = fRefreshValue or (id in [
+            'DEAD0000-BEAF-DEAD-BEAF-EE0000000005',
+            'DEAD0000-BEAF-DEAD-BEAF-EE0000000006',
+            'DEAD0000-BEAF-DEAD-BEAF-EE00000000A5',
+            'DEAD0000-BEAF-DEAD-BEAF-EE00000000A6'
+        ])
+        #if id == '00000000-0000-0000-0000-000000000001':
+        #    self.logger.error("Value change of '"+id+"' detected: "+str(old_value)+" -> "+str(value) + " " + str(fRefreshValue) + " " + str(default))
+        if fRefreshValue:
+            #self.logger.error("Value change of '"+id+"' detected: "+str(old_value)+" -> "+str(value) + " " + str(fRefreshValue) + " " + str(default))
+            if self.logger.level <= logging.DEBUG:
+                self.logger.debug("Value change of '"+id+"' detected: "+str(old_value)+" -> "+str(value))
+            if not default: self.create_event_custprior(priority, "EventValueChange", self.sensors[id].sensor, old_value, value, state)
+        
+        if fRefreshSate:
+            if self.logger.level <= logging.DEBUG:
+                self.logger.debug("State change of '"+id+"' detected: "+str(old_state)+" -> "+str(state))
+            if not default: self.create_event_custprior(priority, "EventStateChange", self.sensors[id].sensor, old_state, state, value)
+            
+        if fRefreshValue or fRefreshSate: self.sensors[id].onChange()
+        SensorHolder.sensors_lock.release()
+        
+    def get_value_pair(self, id, fLock = True):
+        """ Read value pair (value, state) for sensor from corresponding files """
+        value, state = None, None
+        if fLock: SensorHolder.sensors_lock.acquire()
+        try:
+            if id in self.sensors.keys(): value, state = self.sensors[id].value, self.sensors[id].state
+        finally:
+            if fLock: SensorHolder.sensors_lock.release()
+        return (value, state)
+    
+    def get_value_pairs(self, ids):
+        """ Returns id:value/state pairs for list of ids """
+        SensorHolder.sensors_lock.acquire()
+        try:    res = dict(zip(ids, map(lambda x: self.get_value_pair(x, False), ids)))
+        except: res = {}
+        SensorHolder.sensors_lock.release()
+        return res
+    
+    def get_value_descrs(self, values):
+        """ Returns id:description pairs for list of ids """
+        SensorHolder.sensors_lock.acquire()
+        try:    res = dict(zip(values.keys(), map(lambda x: self.get_value_description(x, values[x]), values.keys())))
+        except: res = {}
+        SensorHolder.sensors_lock.release()
+        return res
+    
+    def get_value_pair_and_descr(self, ids):
+        """ Returns id:value/state/description pairs for list of ids """
+        SensorHolder.sensors_lock.acquire()
+        try:
+            res = dict(zip(ids, map(lambda x: self.get_value_pair(x, False), ids)))
+            res = dict(zip(ids, map(lambda x: (res[x][0], res[x][1], self.get_value_description(x, res[x][0])), ids )))
+        except:
+            self.logger.exception("Exception while get_value_pair_and_descr.")
+            res = {}
+        SensorHolder.sensors_lock.release()
+        return res
+    
+    def get_sensor_by_id(self, id):
+        return self.sensors[id].sensor
+    
+    def get_sensor_by_alias(self, alias):
+        for sensor_holder in self.sensors.values():
+            if sensor_holder.sensor.alias == alias:
+                return sensor_holder.sensor
+        raise Exception("sensor {0} not found".format(alias))
+    
+    def get_sensor_id_by_alias(self, alias):
+        for sensor_holder in self.sensors.values():
+            if sensor_holder.sensor.alias == alias:
+                return sensor_holder.sensor.id
+        raise Exception("sensor {0} not found".format(alias))
+    
+    def update_snmp_sensor(self, id):
+        """ Immidiate update of snmp sensor. Blocking. """
+        try: self.get_sensor_by_id(id).immidiate_update()
+        except: self.logger.exception("Exception while update_snmp_sensor")
+    
+    """ ToDo: rename this to event_taker """
+    def subscribe(self, _class, _event, _handler):
+        """ Register new handler for some sensor """
+        self.queue_event.subscribe(_class, _event, _handler)
+    
+    def action_taker(self, _class, _event, _handler):
+        """ Register new handler for some sensor """
+        self.queue_action.subscribe(_class, _event, _handler)
+    
+    def put_message(self, _queue, _class, _priority, *_args):
+        """ Create action or event message for some subsystem. _class - string with event class name. """
+        """ _args - will be translate to command. if [0] (sender) = None, we set it as self """
+        if (len(_args) >= 1):
+            if (len(_class) > 2) and (_class[-2:] != "\Z"): _class += "\Z"  
+            if self.logger.level <= logging.INFO:
+                self.logger.info("Try to generate event '"+str(_class)+"' for '"+str(_args[0])+"'...")
+            classes = self.event_modules.class_by_regexp(_class)
+            if len(classes) == 1:
+                if (len(_args) >= 1) and (_args[0] == None): _args = (self,)+_args[1:]
+                try:    _queue.put(classes[0](*_args))
+                except: self.logger.exception("Exception while creating event class '"+_class+"'")
+            else: self.logger.error("Loading event "+_class+" - FAIL, no or too many classes ("+str(classes)+")")
+        else: self.logger.error("Not enough arguments to create event '"+_class+"' - FAIL")
+    
+    def create_event(self, _class, *_args):
+        self.put_message(self.queue_event, _class, MessageQueue.PRIOR_LOWEST, *_args)
+
+    def create_event_hiprior(self, _class, *_args):
+        self.put_message(self.queue_event, _class, MessageQueue.PRIOR_HIGHEST, *_args)
+    
+    def create_event_custprior(self, _prior, _class, *_args):
+        if _prior == None: _prior = MessageQueue.PRIOR_LOWEST
+        self.put_message(self.queue_event, _class, _prior, *_args)
+    
+    def create_action(self, _class, *_args):
+        self.put_message(self.queue_action, _class, MessageQueue.PRIOR_LOWEST, *_args)
+    
+    """ ToDo: maybe move this to some power-helper """
+    def is_battery_present(self):
+        try: return self.get_sensor_by_alias("BAT").is_battery_present()
+        except: return False
+    
+    """ --- This two routines for compatibility, and for raw Event/Action class put --- """
+    def put_action(self, action, priority = None):
+        """ Put action element in queue """
+        if priority == None: priority = MessageQueue.PRIOR_LOWEST
+        self.queue_action.put(action, priority)
+
+    def put_event(self, event, priority = None):
+        """ Put event element in queue """
+        if priority == None: priority = MessageQueue.PRIOR_LOWEST
+        self.queue_event.put(event)
+    
+    def load_sensor(self, id, descr):
+        """ Create sensor from configuration description and put it in self.sensors """
+        """ WARNING! By default this function works only with NEW configuration. """
+        """  For newly added sensor please use load_new_sensor, to save/deserialize configuration. """
+        try:
+            self.logger.info("Try to load sensor "+id+"...")
+            sensor_classes = self.sensor_modules.class_by_regexp(descr["sensor_class"]+"\Z")
+            if len(sensor_classes) == 1:
+                try:
+                    self.logger.debug("Found sensor class '"+str(sensor_classes[0].__name__)+"' for sensor "+id+", creating...")
+                    self.sensors[id] = SensorHolder(sensor_classes[0](self.configman, self, id))
+                    return True
+                except: self.logger.exception("Exception while creating sensor class '"+str(sensor_classes[0])+"', id "+id)
+            else: self.logger.error("Loading sensor "+id+" - FAIL, no such class: "+descr["sensor_class"]+" or too many classes ("+str(sensor_classes)+")")
+        except: self.logger.exception("Exception while searching for sensor with description '"+str(descr)+"'")
+        return False
+
+    def load_new_sensor(self, id, class_name):
+        fake_descr = {"sensor_class":class_name}
+        if self.load_sensor(id, fake_descr):
+            self.start_sensor(id)
+            self.configman.confirm_path(["sensors", id])
+            return True
+        return False
+    
+    def confirm_sensors(self):
+        self.configman.confirm_path(["sensors"])
+    
+    def delete_sensor(self, id):
+        result = False
+        self.sensors[id].sensor.stop()
+        SensorHolder.sensors_lock.acquire()
+        try:
+            self.sensors[id].sensor.delete()
+            del self.sensors[id]
+        except: self.logger.exception("Exception while delete sensor '"+str(id)+"'")
+        finally: SensorHolder.sensors_lock.release()
+        
+        try:
+            """ This must not be under lock """
+            sensors = make_copy(self.configman.read_config(["sensors"]))
+            del sensors[id]
+            self.configman.write_config(["sensors"], sensors)
+            result = True
+        except: self.logger.exception("Exception while delete sensor '"+str(id)+"'")
+        return result
+    
+    def delete_sensor_device(self, sensor_id):
+        result = False
+        ids = []
+        try:
+            device_sensors = [sensor for sensor in self.sensors[sensor_id].sensor.get_device_sensors()]
+            self.sensors[sensor_id].sensor.remove_device()
+        except: 
+            self.logger.exception("Exception while delete device '"+str(sensor_id)+"'")
+        
+        try:
+            """ This must not be under lock """
+            sensors = make_copy(self.configman.read_config(["sensors"]))
+            aliases = []
+            for sensor in device_sensors:
+                try:
+                    self.logger.debug("delete sensor '"+str(sensor.id)+"'")
+                    aliases.append(sensor.alias)
+                    del sensors[sensor.id]
+                    del self.sensors[sensor.id]
+                except:
+                    self.logger.exception("Exception while delete sensor '"+str(sensor.id)+"'")
+            self.configman.write_config(["sensors"], sensors)
+            try:
+                self.set_send_inform_flag(aliases, False)
+            except:
+                self.logger.exception("can't set inform flag")
+            result = True
+        except: self.logger.exception("Exception while delete device '"+str(sensor_id)+"'")
+        return result
+    
+    def get_controller_state(self):
+        sensor = self.get_sensor_by_alias("CNT")
+        value = self.get_value_pair(sensor.id)[0]
+        return self.get_value_description(sensor.id, value).get("caption", "n/a")
+
+    def get_Sig(self, teploAPI=None):
+        def get_sensor_state(alias):
+            return self.get_sensor_state_by_alias(alias) == 'almaj'
+        
+        events_functions = {
+            0: [lambda: get_sensor_state("VIBlis")],
+            1: [lambda: self.get_sensor_value_by_alias("teploUB.pwr") in ("DISCHARGING", "SHUTDOWN")],
+            2: [lambda: get_sensor_state("DI1")],
+            3: [lambda: get_sensor_state("DI2")],
+            4: [lambda: get_sensor_state("DI3")],
+            5: [lambda: get_sensor_state("DI4")],
+            6: [lambda: get_sensor_state("teploUB.extDS1")],
+            7: [lambda: teploAPI is not None and not teploAPI.check_serial_numbers()],
+        } 
+        
+        sig = 0
+        for bit, func_list in events_functions.items():
+            sig |= any(func() for func in func_list) << bit
+        return sig
+
+    def get_sensor_description_by_alias(self, alias): #description
+        sensor = self.get_sensor_by_alias(alias)
+        value = self.get_value_pair(sensor.id)[0]
+        return self.get_value_description(sensor.id, value).get("caption", "n/a")
+    
+    def get_sensor_state_by_alias(self, alias):
+        sensor = self.get_sensor_by_alias(alias)
+        return self.get_value_pair(sensor.id)[1]
+    
+    def get_sensor_value_by_alias(self, alias):
+        sensor = self.get_sensor_by_alias(alias)
+        return self.get_value_pair(sensor.id)[0]
+    
+    def find_free_alias(self, pattern):
+        """ ToDo: merge with same function of event monitor (load_sensors) and move to configman """
+        res = set(range(1, 999))
+        try:
+            self.logger.debug("Search for free aliases...")
+            all_sensors = self.configman.read_config(["sensors"])
+            for sensor in all_sensors.keys():
+                try:
+                    self.logger.debug("matching sensor ID \'{0}\' alias \'{1}\'".format(sensor, all_sensors[sensor]["alias"]))
+                    matched = re.match(pattern, all_sensors[sensor]["alias"])
+                    if matched:
+                        self.logger.debug("\tAllready have sensor ID '"+sensor+"'")
+                        num = int(matched.group("num"), 10)
+                        self.logger.debug("removing {0}".format(num))
+                        if num in res:
+                            res.remove(num)
+                except: 
+                    self.logger.exception("Exception while scan aliases '"+str(sensor)+"'")
+        except: 
+            self.logger.exception("Exception while read sensors configuration")
+        return res # This is bad - on exception will return full range 
+    
+    def set_send_inform_flag(self, aliases, flag):
+        try:
+            change_state_trigger = self.configman.read_config(self.STATE_CHANGE_TRIGGER_PATH, copy_=True)
+            for alias in aliases:
+                if len(change_state_trigger) == 0:
+                    change_state_trigger.append("or")
+                trigger = [
+                   "sensor_state",
+                    alias
+                ]
+                if flag:
+                    if trigger not in change_state_trigger:
+                        change_state_trigger.append(trigger)
+                else:
+                    try:
+                        change_state_trigger.remove(trigger)
+                    except Exception as e: self.logger.warning("No sensor for trigger "+str(trigger))
+            self.configman.write_config(self.STATE_CHANGE_TRIGGER_PATH, change_state_trigger)
+        except:
+            self.logger.exception("set_send_snmp_flag exception")

+ 74 - 0
courses/python_for_begginers/sort.py

@@ -0,0 +1,74 @@
+
+a = [42, 23, 66, 42, 93, 47, 30]
+b = 'dsf aaerwq dfasdf '
+c = ('sdf', 'sdqwet', 'ghetrertg')
+
+# метод .sort возвращает None
+new_list = a
+new_list = new_list.sort()
+# print(new_list)
+
+# Принимает любую итерабельную последовательность
+# Не изменяет начальную коллекцию
+# Возвращает список
+sorted(a)
+
+
+sorted_string = sorted(b, reverse=True)
+sorted_tuple = sorted(c)
+
+# print(sorted_string)
+# print(sorted_tuple)
+# print(sorted(a))
+
+
+# Сортировка будет происходить по двум признакам последовательно
+def foo(x):
+	return x%10, x//10%10
+
+# print(sorted(a, key=foo))
+
+
+my_list_1 = ['ZZZ 5', 'aaa 7', 'BBB 23', 'www 45', 'EEE 5', 'ddd 5']
+
+# print(sorted(my_list_1, key = str.lower))
+# print(sorted(my_list_1, key = lambda x: (int(x.split()[1]), x.split()[0].lower() )))
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+# subject_marks = [('English', 88), ('Science', 90), ('Maths', 97), ('Physics', 93),('History', 82)]
+
+subject_marks = [('English', 88), ('Science', 90), ('Maths', 88),
+                 ('Physics', 93), ('History', 78), ('French', 78),
+                 ('Art', 78), ('Chemistry', 88), ('Programming', 91)]
+
+# subject_marks = sorted(subject_marks, key = lambda x: x[1])
+# for key, value in subject_marks:
+# 	print(key, value)
+
+
+# subject_marks = sorted(subject_marks, key = lambda x: x[1], reverse=True)
+# for key, value in subject_marks:
+# 	print(key, value)
+
+
+# subject_marks = sorted(subject_marks, key = lambda x: (-x[1], x[0]))
+# for key, value in subject_marks:
+# 	print(key, value)
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+heroes = {
+    'Spider-Man': 80,
+    'Batman': 65,
+    'Superman': 85,
+    'Wonder Woman': 70,
+    'Flash': 70,
+    'Iron Man': 65,
+    'Thor': 90,
+    'Aquaman': 65,
+    'Captain America': 65,
+    'Hulk': 87,
+}
+

+ 0 - 11
cpp.code-workspace

@@ -1,11 +0,0 @@
-{
-	"folders": [
-		{
-			"path": "cpp"
-		},
-		{
-			"path": "courses/python_for_begginers"
-		}
-	],
-	"settings": {}
-}

+ 2 - 0
docs/arbiter_ip.txt

@@ -0,0 +1,2 @@
+jsonrpc server:
+	API

+ 76 - 0
jsonrpc/jsonrpc_test.py

@@ -0,0 +1,76 @@
+import jsonrpclib
+from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
+import threading
+import time
+
+
+SERVER_ADDR = ("localhost", 7000)
+
+class JSONRPCServer:
+
+	def __init__(self):
+		self.server = SimpleJSONRPCServer(SERVER_ADDR)
+		self.service = ExampleAggregateService()
+		self.server.register_instance(self.service, allow_dotted_names=True)
+		self.server.register_function(self.service.sumation, 'sum')
+		self.server.register_function(self.service.sumation, 'notify_sum')
+		self.server.register_function(self.service.sumation, 'namespace.sum')
+		# self.server.register_introspection_functions()
+		# self.JSONRPC_server.register_function(lambda x, y: x + y, 'add')
+		self.thread = threading.Thread(self.server.serve_forever)
+		self.thread.daemon = True
+		self.thread.stop = self.stop
+		self.thread.start()
+		# self._wait_for_rpc_start() 
+		# time.sleeep(3)
+
+	def _wait_for_rpc_start(self):
+		rpc = jsonrpclib.Server("http://{0}:{1}".format(SERVER_ADDR[0], SERVER_ADDR[1]))
+		while True:
+			try:
+				if rpc.ping():
+					print("Ping JSONRPCServer successfull")
+					return
+			except:
+				pass
+			time.sleep(1)
+
+	def stop(self):
+		self.server.shutdown()
+
+
+
+class JSONRPCClient:
+
+	def __init__(self) -> None:
+		self.client = jsonrpclib.Server("http://{0}:{1}".format(SERVER_ADDR[0], SERVER_ADDR[1]))
+
+
+class ExampleService:
+	
+	@staticmethod
+	def add(x, y):
+		return x + y
+
+	@staticmethod
+	def sumation(*args):
+		return sum(args)
+
+	@staticmethod
+	def get_data():
+		return ['hello', 5]
+	
+	def ping():
+		return True
+
+
+class ExampleAggregateService(ExampleService):
+	
+	def __init__(self) -> None:
+		self.sub_service = ExampleService()
+
+
+
+server = JSONRPCServer()		
+client = JSONRPCClient()
+print(client.ping())