| 1 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  *  PyDMXControl: A Python 3 module to control DMX using OpenDMX or uDMX. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |  *                Featuring fixture profiles, built-in effects and a web control panel. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  *  <https://github.com/MattIPv4/PyDMXControl/> | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  |  *  Copyright (C) 2023 Matt Cowley (MattIPv4) ([email protected]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | from datetime import datetime | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | from typing import Union, Tuple, List | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | from ._Fixture import Fixture | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | class Vdim(Fixture): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |     def __init__(self, *args, **kwargs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |         super().__init__(*args, **kwargs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |         self.__vdims = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         self.__vdim = 255 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         self.__vdim_timestamp = datetime.utcnow() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         self.__vdim_parked = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |     def __vdim_updated(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         self.__vdim_timestamp = datetime.utcnow() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |     def _register_channel(self, name: str, *, parked: Union[bool, int] = False, vdim: bool = False) -> int: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |         super_call = super()._register_channel(name, parked=parked) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |         # Register vdim if applicable | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |         if vdim: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |             self.__vdims.append(super_call) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |         return super_call | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |     def __is_vdim_channel(self, channel: Union[str, int]) -> bool: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         return str(channel).lower().strip() in ["dimmer", "vdim", "dim", "d"] \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |                or str(channel) == str(self.next_channel - 1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     def get_channel_id(self, channel: Union[str, int]) -> int: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |         # Look for vdim channel | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |         if self.__is_vdim_channel(channel): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |             return self.next_channel - 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |         # Get normal channel | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         return super().get_channel_id(channel) | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 47 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 48 |  |  |     def get_channel_value(self, channel: Union[str, int], apply_vdim: bool = True, apply_parking: bool = True) -> Tuple[int, datetime]: | 
            
                                                                        
                            
            
                                    
            
            
                | 49 |  |  |         # Look for vdim channel | 
            
                                                                        
                            
            
                                    
            
            
                | 50 |  |  |         if self.__is_vdim_channel(channel): | 
            
                                                                        
                            
            
                                    
            
            
                | 51 |  |  |             return (self.__vdim if (not apply_parking) or (self.__vdim_parked is False) else self.__vdim_parked), self.__vdim_timestamp | 
            
                                                                        
                            
            
                                    
            
            
                | 52 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 53 |  |  |         # Get normal channel | 
            
                                                                        
                            
            
                                    
            
            
                | 54 |  |  |         super_call = super().get_channel_value(channel, apply_parking) | 
            
                                                                        
                            
            
                                    
            
            
                | 55 |  |  |         new_val = super_call[0] | 
            
                                                                        
                            
            
                                    
            
            
                | 56 |  |  |         new_time = super_call[1] | 
            
                                                                        
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 58 |  |  |         # Apply vdim if applicable | 
            
                                                                        
                            
            
                                    
            
            
                | 59 |  |  |         if apply_vdim and self.get_channel_id(channel) in self.__vdims: | 
            
                                                                        
                            
            
                                    
            
            
                | 60 |  |  |             new_val = int(new_val * (self.__vdim / 255)) | 
            
                                                                        
                            
            
                                    
            
            
                | 61 |  |  |             if self.__vdim_timestamp > new_time: | 
            
                                                                        
                            
            
                                    
            
            
                | 62 |  |  |                 new_time = self.__vdim_timestamp | 
            
                                                                        
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 64 |  |  |         return new_val, new_time | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |     def set_channel(self, channel: Union[str, int], value: int) -> Fixture: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         # Allow setting of vdim | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         if self.__is_vdim_channel(channel): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             return self.set_vdim(value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |         # Set normal channel | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |         return super().set_channel(channel, value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |     def set_vdim(self, value: int) -> Fixture: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         # Update the vdim value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         if not self._valid_channel_value(value, 'vdim'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |             return self | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         self.__vdim = value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         # If not parked, bump the timestamp | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |         if self.__vdim_parked is False: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |             self.__vdim_updated() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         return self | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |     def get_color(self) -> Union[None, List[int]]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |         if not self.has_channel('r') or not self.has_channel('g') or not self.has_channel('b'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |         color = [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |             self.get_channel_value('r', False, False)[0], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             self.get_channel_value('g', False, False)[0], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |             self.get_channel_value('b', False, False)[0], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |         if self.has_channel('w'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             color.append(self.get_channel_value('w', False, False)[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |             if self.has_channel('a'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |                 color.append(self.get_channel_value('a', False, False)[0]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |         return color | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |     def park(self) -> Fixture: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |         self.__vdim_parked = self.__vdim | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |         self.__vdim_updated() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         return super().park() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     def unpark(self) -> Fixture: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |         if self.__vdim_parked is not False: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |             self.__vdim_parked = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |             self.__vdim_updated() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 115 |  |  |         return super().unpark() | 
            
                                                        
            
                                    
            
            
                | 116 |  |  |  |