diff --git a/NooLite_F/MTRF64/MTRF64Controller.py b/NooLite_F/MTRF64/MTRF64Controller.py index af7d183..0e768a5 100644 --- a/NooLite_F/MTRF64/MTRF64Controller.py +++ b/NooLite_F/MTRF64/MTRF64Controller.py @@ -27,7 +27,7 @@ def parse(response: IncomingData) -> ModuleInfo: class MTRF64Controller(NooLiteFController): _adapter = None - _listener_map: {int: RemoteControllerListener} = {} + _listener_map: {int: [RemoteControllerListener]} = {} _mode_map = { ModuleMode.NOOLITE: Mode.TX, @@ -37,6 +37,11 @@ class MTRF64Controller(NooLiteFController): def __init__(self, port: str): self._adapter = MTRF64USBAdapter(port, self._on_receive) + def release(self): + self._adapter.release() + self._adapter = None + self._listener_map = {} + # Private def _command_mode(self, module_mode: ModuleMode) -> Mode: return self._mode_map[module_mode] @@ -219,15 +224,32 @@ def service_mode_on(self, module_id: int = None, channel: int = None, broadcast: def service_mode_off(self, module_id: int = None, channel: int = None, broadcast: bool = False, module_mode: ModuleMode = ModuleMode.NOOLITE_F) -> [(bool, ModuleInfo)]: return self._send_module_command(module_id, channel, Command.SERVICE, broadcast, self._command_mode(module_mode)) - def set_listener(self, channel: int, listener: RemoteControllerListener): - self._listener_map[channel] = listener + def add_listener(self, channel: int, listener: RemoteControllerListener): + listeners: [RemoteControllerListener] = self._listener_map.get(channel, []) + listeners.append(listener) + + self._listener_map[channel] = listeners + print(self._listener_map) + + def remove_listener(self, channel: int, listener: RemoteControllerListener): + listeners: [RemoteControllerListener] = self._listener_map.get(channel, []) + listeners.remove(listener) + if len(listeners) == 0: + listeners = None + + self._listener_map[channel] = listeners print(self._listener_map) # Listeners def _on_receive(self, incoming_data: IncomingData): - listener: RemoteControllerListener = self._listener_map.get(incoming_data.channel, None) + listeners: [RemoteControllerListener] = self._listener_map.get(incoming_data.channel, None) + + if listeners is None: + return - if listener is not None: + for listener in listeners: + if listener is None: + return if incoming_data.command == Command.ON: listener.on_on() @@ -323,6 +345,5 @@ def _on_receive(self, incoming_data: IncomingData): listener.on_temp_humi(temp, humi, battery, analog) elif incoming_data.command == Command.BATTERY_LOW: - listener.on_battery_low() - + listener.on_battery_low() diff --git a/NooLite_F/MTRF64/MTRF64USBAdapter.py b/NooLite_F/MTRF64/MTRF64USBAdapter.py index 3a0e679..aa927d9 100644 --- a/NooLite_F/MTRF64/MTRF64USBAdapter.py +++ b/NooLite_F/MTRF64/MTRF64USBAdapter.py @@ -108,6 +108,7 @@ class MTRF64USBAdapter(object): _incoming_queue = Queue() _listener_thread = None _listener = None + _is_released = False def __init__(self, port: str, on_receive_data=None): self._serial = Serial(baudrate=9600) @@ -124,6 +125,12 @@ def __init__(self, port: str, on_receive_data=None): self._listener_thread.daemon = True self._listener_thread.start() + def release(self): + self._is_released = True + self._serial.close() + self._incoming_queue.put(None) + self._listener = None + def send(self, data: OutgoingData) -> [IncomingData]: responses = [] @@ -187,6 +194,10 @@ def _parse(self, packet: bytes) -> IncomingData: def _read_loop(self): while True: packet = self._serial.read(self._packet_size) + + if self._is_released: + break + try: data = self._parse(packet) print("Receive:\n - packet: {0},\n - data: {1}".format(packet, data)) @@ -202,8 +213,16 @@ def _read_loop(self): print("Packet error: {0}".format(err)) pass + print("Thread 1 finished") + def _read_from_incoming_queue(self): while True: input_data = self._incoming_queue.get() + + if self._is_released: + break + if self._listener is not None: self._listener(input_data) + + print("Thread 2 finished") diff --git a/NooLite_F/NooLiteFController.py b/NooLite_F/NooLiteFController.py index 79b9042..2206097 100644 --- a/NooLite_F/NooLiteFController.py +++ b/NooLite_F/NooLiteFController.py @@ -404,10 +404,26 @@ def service_mode_off(self, module_id: int = None, channel: int = None, broadcast pass @abstractmethod - def set_listener(self, channel: int, listener: RemoteControllerListener): - """ Set the remote controls listener. To remove listener pass None to listener param. + def add_listener(self, channel: int, listener: RemoteControllerListener): + """ Add the remote controls listener to channel. :param channel: channel to which the listener will be assigned :param listener: listener """ pass + + @abstractmethod + def remove_listener(self, channel: int, listener: RemoteControllerListener): + """ Remove the remote controls listener from channel. + + :param channel: channel to which the listener will be assigned + :param listener: listener + """ + pass + + # + # + # on_on, on_off, on_switch, on_load_preset, on_save_preset, on_temporary_on, on_brightness_tune, + # on_brightness_tune_back, on_brightness_tune_stop, on_brightness_tune_custom, on_brightness_tune_step, + # on_set_brightness, on_roll_rgb_color, on_switch_rgb_color, on_switch_rgb_mode, on_switch_rgb_mode_speed, + # on_set_rgb_brightness, on_temp_humi, on_battery_low diff --git a/NooLite_F/Sensors.py b/NooLite_F/Sensors.py index 6a8c83d..24b8200 100644 --- a/NooLite_F/Sensors.py +++ b/NooLite_F/Sensors.py @@ -7,7 +7,11 @@ def __init__(self, controller: NooLiteFController, channel: int, on_battery_low) self._controller = controller self._channel = channel self._battery_low_listener = on_battery_low - self._controller.set_listener(channel, self) + self._controller.add_listener(channel, self) + + def release(self): + self._controller.remove_listener(self._channel, self) + self._controller = None def on_battery_low(self): if self._battery_low_listener is not None: diff --git a/README.rst b/README.rst index 563115c..7c81eb4 100644 --- a/README.rst +++ b/README.rst @@ -198,8 +198,8 @@ So you should not worry about it:: remoteController = MyRemoteController() sensor = MySensor() - controller.set_listener(1, remoteController) - controller.set_listener(2, remoteController) + controller.add_listener(1, remoteController) + controller.add_listener(2, remoteController) Using sensor wrappers @@ -235,10 +235,10 @@ And in the end you can use a special wrappers around Controller and RemoteContro print("switch speed") -controller = MTRF64Controller("COM3") + controller = MTRF64Controller("COM3") -tempSensor = TempHumiSensor(controller, 9, on_temp, on_battery) -rgb = RGBRemoteController(controller, 63, on_switch, on_tune_back, on_tune_stop, on_roll_color, on_switch_color, on_switch_mode, on_switch_speed, on_battery) + tempSensor = TempHumiSensor(controller, 9, on_temp, on_battery) + rgb = RGBRemoteController(controller, 63, on_switch, on_tune_back, on_tune_stop, on_roll_color, on_switch_color, on_switch_mode, on_switch_speed, on_battery) Available wrappers: diff --git a/setup.py b/setup.py index 0945743..d5e4438 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name="NooLite_F", packages=["NooLite_F", "NooLite_F.MTRF64"], - version="0.0.11", + version="0.0.12", license="MIT License", description="Module to work with NooLite/NooLite-F modules via MTRF-64-USB adapter", long_description=long_description,