diff --git a/.gitignore b/.gitignore index a3b008ad0..a14bf54b9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ */*/.DS_store Conf/PluginConf-* OTAFirmware/*/* +certs/* !OTAFirmware/*/README.me !OTAFirmware/*/.PRECIOUS Conf/ZigateGroupsConfig-* diff --git a/Classes/AdminWidgets.py b/Classes/AdminWidgets.py index 87ad01d61..1aca79ac3 100644 --- a/Classes/AdminWidgets.py +++ b/Classes/AdminWidgets.py @@ -39,7 +39,7 @@ def _get_switch_selector_options(self, ): } class AdminWidgets: - def __init__(self, log, PluginConf, pluginParameters, ListOfDomoticzWidget, Devices, ListOfDevices, HardwareID): + def __init__(self, log, PluginConf, pluginParameters, ListOfDomoticzWidget, Devices, ListOfDevices, HardwareID, IEEE2NWK): self.pluginconf = PluginConf self.pluginParameters = pluginParameters @@ -47,6 +47,7 @@ def __init__(self, log, PluginConf, pluginParameters, ListOfDomoticzWidget, Devi self.Devices = Devices # Point to the List of Domoticz Devices self.ListOfDevices = ListOfDevices # Point to the Global ListOfDevices self.HardwareID = HardwareID + self.IEEE2NWK = IEEE2NWK self.log = log self.createStatusWidget(Devices) self.createNotificationWidget(Devices) diff --git a/Classes/LoggingManagement.py b/Classes/LoggingManagement.py index e4c43ddc4..2084d3b12 100644 --- a/Classes/LoggingManagement.py +++ b/Classes/LoggingManagement.py @@ -511,12 +511,12 @@ def process_logging_event( self, logging_tuple): _catch_error_event(self, context,logging_tuple, err ) return - thread_name = f"{thread_name} {thread_id}" - if logType == "Error": + thread_name=thread_name + " " + thread_id loggingError(self, thread_name, module, message, nwkid, context) elif logType == "Debug" and _should_log_debug(self, thread_name) and _is_to_be_logged(self, logType, module): + thread_name=thread_name + " " + thread_id _logginfilter(self, thread_name, message, nwkid) else: diff --git a/Classes/OTA.py b/Classes/OTA.py index b3dc08e36..b23584437 100644 --- a/Classes/OTA.py +++ b/Classes/OTA.py @@ -67,6 +67,7 @@ "Ledvance": {"Folder": "LEDVANCE", "ManufCode": 0x1189, "ManufName": "LEDVANCE", "Enabled": True}, "Legrand": {"Folder": "LEGRAND", "ManufCode": 0x1021, "ManufName": "Legrand", "Enabled": True}, "Lixee": {"Folder": "LIXEE", "ManufCode": 0x1037, "ManufName": "LiXee", "Enabled": True}, + "Nodon": {"Folder": "NODON", "ManufCode": 0x128b, "ManufName": "NodOn", "Enabled": True}, "Osram1": {"Folder": "OSRAM", "ManufCode": 0xBBAA, "ManufName": "OSRAM", "Enabled": True}, "Osram2": {"Folder": "LEDVANCE", "ManufCode": 0x110C, "ManufName": "OSRAM", "Enabled": True}, "Philips": {"Folder": "PHILIPS", "ManufCode": 0x100B, "ManufName": "Philips", "Enabled": True}, diff --git a/Classes/PluginConf.py b/Classes/PluginConf.py index 1e15f9c8a..54e3cafa2 100644 --- a/Classes/PluginConf.py +++ b/Classes/PluginConf.py @@ -210,6 +210,8 @@ "pluginReports": {"type": "path","default": "","current": None,"restart": 1,"hidden": False,"Advanced": True,}, "pluginWWW": {"type": "path","default": "","current": None,"restart": 1,"hidden": False,"Advanced": True,}, "pluginLogs": {"type": "path","default": "","current": None,"restart": 1,"hidden": False,"Advanced": True,}, + "SSLCertificate": {"type": "path","default": "","current": None,"restart": 1,"hidden": False,"Advanced": True,}, + "SSLPrivateKey": {"type": "path","default": "","current": None,"restart": 1,"hidden": False,"Advanced": True,}, }, }, # Verbose @@ -218,6 +220,7 @@ "param": { "AbstractDz": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "Barometer": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, + "BatteryManagement": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "BasicOutput": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "Binding": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "CasaIA": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, @@ -285,6 +288,8 @@ "ReadAttributes": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "Schneider": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "Sonoff": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, + "Sunricher": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, + "Temperature": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "Thermostats": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, "ThreadCommunication": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True }, @@ -653,7 +658,7 @@ def _path_check(self): # this is a url continue _path_name = Path( self.pluginConf[param] ) - if not os.path.exists(_path_name): + if param not in ( "SSLCertificate", "SSLPrivateKey") and not os.path.exists(_path_name): Domoticz.Error("Cannot access path: %s" % _path_name) if self.pluginConf[param] != str( _path_name ): if self.pluginConf["PosixPathUpdate"]: @@ -716,5 +721,9 @@ def setup_folder_parameters(self, homedir): self.pluginConf[param] = str( Path(self.pluginConf["pluginHome"]) / "Reports") elif param == "pluginWWW": self.pluginConf[param] = str( Path(self.pluginConf["pluginHome"]) / "www") + elif param == "SSLCertificate": + self.pluginConf[param] = str( Path(self.pluginConf["pluginHome"]) / "certs" / "server.crt") + elif param == "SSLPrivateKey": + self.pluginConf[param] = str( Path(self.pluginConf["pluginHome"]) / "certs" / "server.key") else: self.pluginConf[param] = SETTINGS[theme]["param"][param]["default"] diff --git a/Classes/WebServer/WebServer.py b/Classes/WebServer/WebServer.py index e42ce3623..1c00e0b22 100644 --- a/Classes/WebServer/WebServer.py +++ b/Classes/WebServer/WebServer.py @@ -186,6 +186,12 @@ def __init__( self.DomoticzMajor = DomoticzMajor self.DomoticzMinor = DomoticzMinor + + self.server_thread = None + self.client_threads = [] + self.running = None + self.clients = {} + # httpPort could have 2 formats. port number only or IP:port if ':' in httpPort: @@ -854,10 +860,9 @@ def rest_zDevice_name(self, verb, data, parameters): del self.IEEE2NWK[ieee] # for a remove in case device didn't send the leave - if "IEEE" in self.ControllerData and ieee: + if ieee and "IEEE" in self.ControllerData and self.zigbee_communication == "native": # uParrentAddress + uChildAddress (uint64) - if self.zigbee_communication == "native": - sendZigateCmd(self, "0026", self.ControllerData["IEEE"] + ieee) + sendZigateCmd(self, "0026", self.ControllerData["IEEE"] + ieee) action = {"Name": "Device %s/%s removed" % (nwkid, ieee)} _response["Data"] = json.dumps(action, sort_keys=True) diff --git a/Classes/WebServer/com.py b/Classes/WebServer/com.py index 4efe059f4..6b5a3c0ee 100644 --- a/Classes/WebServer/com.py +++ b/Classes/WebServer/com.py @@ -4,94 +4,464 @@ # Author: zaraki673 & pipiche38 # +import os +import socket +import ssl +import threading +import traceback + from Modules.domoticzAbstractLayer import domoticz_connection +from Classes.WebServer.tools import MAX_BLOCK_SIZE def startWebServer(self): - # self.httpPort = '9440' - # self.httpIp = None or IP Adress to be bind - # self.httpPort = httpPort + self.logging("Status", "WebUI thread started") + if self.server_thread: + self.logging("Error", "start_logging_thread - Looks like logging_thread already started !!!") + return - if self.httpIp is None: - self.httpServerConn = domoticz_connection( name="Zigate Server Connection", transport="TCP/IP", protocol="HTTP", port=self.httpPort) - else: - self.httpServerConn = domoticz_connection( name="Zigate Server Connection", transport="TCP/IP", protocol="HTTP", address=str(self.httpIp), port=self.httpPort ) + # Create and start the server thread + self.server_thread = threading.Thread( name="ZigbeeWebUI_%s" % self.hardwareID, target=run_server, args=(self,) ) + self.server_thread.daemon = True # This makes the thread exit when the main program exits + self.server_thread.start() - self.httpServerConn.Listen() - if self.httpIp is None: - self.logging("Status", "Web backend for Web User Interface started on port: %s" % self.httpPort) - else: - self.logging("Status", "Web backend for Web User Interface started on port: %s:%s" % (self.httpIp, self.httpPort)) - self.logging("Debug", "%s" %( self.httpServerConn)) +def close_all_clients(self): + self.logging("Log", "Closing all client connections...") + for client_addr, client_socket in self.clients.items(): + self.logging("Log", f" - Closing {client_addr}") + client_socket.close() + self.clients.clear() - # self.httpsPort = '9443' - # self.httpsServerConn = Domoticz.Connection(Name="Zigate Server Connection", Transport="TCP/IP", Protocol="HTTPS", Port=self.httpsPort) - # self.httpsServerConn.Listen() - # self.logging( 'Status', "Web backend for Web User Interface started on port: %s" %self.httpsPort)len(fileContent))+" bytes will be returned") +def parse_http_request(data): + """ + Parse an HTTP request string into its components. -def onConnect(self, Connection, Status, Description): + This function splits the HTTP request data into the request line, headers, and body. It assumes that + the data follows the standard HTTP request format. - self.logging("Debug", "Connection: %s, description: %s" % (Connection, Description)) - if Status != 0: - self.logging("Error", f"onConnect - Failed to connect ({str(Status)} to: {Connection.Address} : {Connection.Port} with error: {Description}") - return + Args: + data (str): The HTTP request data as a string. - if Connection is None: - self.logging("Error", "onConnect - Uninitialized Connection !!! %s %s %s" % (Connection, Status, Description)) - return + Returns: + tuple: A tuple containing: + - method (str): The HTTP method (e.g., 'GET', 'POST'). + - path (str): The requested path (e.g., '/index.html'). + - headers (dict): A dictionary of headers where keys are header names and values are header values. + - body (bytes): The body of the request as a bytes object. - # Search for Protocol - for item in str(Connection).split(","): - if item.find("Protocol") != -1: - label, protocol = item.split(":") - protocol = protocol.strip().strip("'") - self.logging("Debug", "%s:>%s" % (label, protocol)) - - if protocol == "HTTP": - # http connection - if Connection.Name not in self.httpServerConns: - self.logging("Debug", "New Connection: %s" % (Connection.Name)) - self.httpServerConns[Connection.Name] = Connection - elif protocol == "HTTPS": - # https connection - if Connection.Name not in self.httpsServerConns: - self.logging("Debug", "New Connection: %s" % (Connection.Name)) - self.httpServerConns[Connection.Name] = Connection - else: - self.logging("Error","onConnect - unexpected protocol for connection: %s" % (Connection)) - - self.logging("Debug", "Number of http Connections : %s" % len(self.httpServerConns)) - self.logging("Debug", "Number of https Connections : %s" % len(self.httpsServerConns)) + Raises: + ValueError: If the request line is malformed or the headers cannot be parsed correctly. + """ + lines = data.split("\r\n") + request_line = lines[0].strip() + method, path, http_proto = request_line.split(" ", 2) -def onDisconnect(self, Connection): + headers = {} + body = "" + + # Parse headers + for line in lines[1:]: + if not line.strip(): + break + key, value = line.split(":", 1) + headers[key.strip()] = value.strip() + + # Parse body if present + if "Content-Length" in headers: + content_length = int(headers["Content-Length"]) + body = lines[-1] if content_length > 0 else "" + + return method, path, headers, body + + +def receive_data(self, client_socket, length=None): + """ + Receive data from the client socket. + + Parameters: + - client_socket: The socket from which to receive data. + - length: The specific amount of data to receive (optional). + + Returns: + - The received data as bytes. + """ + chunks = [] + bytes_recd = 0 + try: + while not (length and bytes_recd >= length): + chunk = client_socket.recv(min(MAX_BLOCK_SIZE, length - bytes_recd) if length else MAX_BLOCK_SIZE) + + if not chunk: + self.logging("Debug", "receive_data ----- No Data received!!!") + break + self.logging("Debug", f"receive_data ----- read {len(chunk)}") + chunks.append(chunk) + bytes_recd += len(chunk) + if len(chunk) < MAX_BLOCK_SIZE: + break + + except socket.error as e: + self.logging("Debug", f"receive_data - Socket error with: {e}") + return b"" + + self.logging("Debug", f"receive_data ----- received {len(chunks)} chuncks") + + return b"".join(chunks) + + +def handle_client(self, client_socket, client_addr): + """ + Handle an individual client connection. + + This method manages the interaction with a client, including receiving data, + parsing HTTP requests, decoding the data, and invoking the appropriate message + handler. It handles timeouts, socket errors, and unexpected exceptions gracefully, + ensuring the client connection is closed properly. + + Args: + client_socket (socket.socket): The socket object representing the client connection. + client_addr (tuple): The address of the client. + + Steps: + 1. Log the connection and add the client socket to the clients dictionary. + 2. Set a timeout on the client socket. + 3. Enter a loop to handle incoming data while the server is running. + 4. Receive data from the client, decode it, and parse the HTTP request. + 5. Decode the HTTP data and call the onMessage handler. + 6. Handle socket timeouts, errors, and unexpected exceptions. + 7. Remove the client from the clients dictionary and close the socket on exit. + + Exceptions: + socket.timeout: Logs and continues on socket timeout. + socket.error: Logs and breaks the loop on socket error. + Exception: Logs and breaks the loop on any other unexpected error. + """ + self.logging("Debug", f"handle_client from {client_addr} {client_socket}") + self.clients[str(client_addr)] = client_socket + + client_socket.settimeout(1) + try: + while self.running: + try: + # Let's receive the first chunck (to get the headers) + data = receive_data(self, client_socket).decode('utf-8') + + if not data: + self.logging("Debug", f"no data from {client_addr}") + break + + method, path, headers, body = parse_http_request(data) + content_length = int(headers.get('Content-Length', 0)) + + self.logging("Debug", f"handle_client from method: {method} path: {path} content_length: {content_length} len_body: {len(body)} headers: {headers}") + + received_length = len(body) + + while received_length <= content_length: + self.logging("Debug", f"handle_client received_length: {received_length} content_length: {content_length} {content_length - received_length}") + additional_data = receive_data(self, client_socket, content_length - len(body)).decode('utf-8') + if not additional_data: + self.logging("Debug", f"no additional_data from {client_addr}") + break + body += additional_data + received_length += len(additional_data) + + self.logging("Debug", f"handle_client content_length: {content_length} len_body: {len(body)}") + Data = decode_http_data(self, method, path, headers, body.encode('utf-8')) + self.onMessage(client_socket, Data) + + except socket.timeout: + self.logging("Debug", f"Socket timeout {client_addr}") + continue + + except socket.error as e: + self.logging("Debug", f"Socket error with {client_addr}: {e}") + break + + except Exception as e: + self.logging("Log", f"Unexpected error with {client_addr}: {e}") + self.logging("Log", f"{traceback.format_exc()}") + break + + finally: + self.logging("Debug", f"Closing connection to {client_addr}.") + if str(client_addr) in self.clients: + del self.clients[str(client_addr)] + client_socket.close() + + +def check_cert_and_key(self, cert_path, key_path): + """ + Check for the existence and validity of the SSL certificate and key files. + + This method verifies that the specified certificate and key files exist and are + correctly formatted for use in an SSL context. If the certificate or key files + are missing or invalid, SSL will not be enabled. + + Args: + cert_dir (str): The directory where the certificate and key files are located. + cert_filename (str): The filename of the certificate file. Defaults to "server.crt". + key_filename (str): The filename of the key file. Defaults to "server.key". + + Returns: + ssl.SSLContext or None: An SSL context if the certificate and key files are valid, + None otherwise. + + Steps: + 1. Construct full paths to the certificate and key files. + 2. Check if the certificate directory exists. + 3. Check if the certificate and key files exist. + 4. Attempt to load the certificate and key files into an SSL context to verify correctness. + 5. Log appropriate messages at each step for missing or invalid files. + 6. Return the SSL context if successful, or None if there are errors. + + Exceptions: + ssl.SSLError: Logs SSL-specific errors encountered during certificate and key loading. + Exception: Logs any other general errors encountered during the process. + """ + # Check if cert and key files exist + if not os.path.exists(cert_path): + self.logging( "Log",f"Certificate file '{cert_path}' does not exist.") + return None + + if not os.path.exists(key_path): + self.logging( "Log",f"Key file '{key_path}' does not exist.") + return None + + try: + # Attempt to load cert and key to verify correctness + context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + context.load_cert_chain(certfile=cert_path, keyfile=key_path) + + except ssl.SSLError as e: + self.logging( "Error",f"SSL error: {e}") + return None + + except Exception as e: + self.logging( "Error",f"Error: {e}") + return None + + self.logging( "Debug", "Certificate and key files exist and are correct.") + return context + + +def set_keepalive(sock, keepalive_time=60, keepalive_interval=10, keepalive_probes=5): + """ + Enable TCP keep-alive on a socket and configure keep-alive parameters. - self.logging("Debug", "onDisconnect %s" % (Connection)) + This function enables the TCP keep-alive mechanism on the specified socket + and sets the parameters for keep-alive probes. Keep-alive helps to detect + broken connections by sending periodic probes when the connection is idle. - if Connection.Name in self.httpServerConns: - self.logging("Debug", "onDisconnect - removing from list : %s" % Connection.Name) - del self.httpServerConns[Connection.Name] - elif Connection.Name in self.httpsServerConns: - self.logging("Debug", "onDisconnect - removing from list : %s" % Connection.Name) - del self.httpsServerConns[Connection.Name] - else: - # Most likely it is about closing the Server - self.logging("Log", "onDisconnect - Closing %s" % Connection) + Parameters: + sock (socket.socket): The socket on which to enable keep-alive. + keepalive_time (int, optional): The time (in seconds) the connection needs to remain + idle before TCP starts sending keep-alive probes. + Default is 60 seconds. + keepalive_interval (int, optional): The time (in seconds) between individual keep-alive probes. + Default is 10 seconds. + keepalive_probes (int, optional): The maximum number of keep-alive probes TCP should send before + dropping the connection. Default is 5 probes. + + Notes: + - The availability of keep-alive parameters (TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT) + may vary based on the operating system. + - This function does not guarantee keep-alive will be effective on all platforms; + it sets parameters only if the platform supports them. + """ + + sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + + # The following options are platform-dependent. + if hasattr(socket, 'TCP_KEEPIDLE'): + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, keepalive_time) + if hasattr(socket, 'TCP_KEEPINTVL'): + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, keepalive_interval) + if hasattr(socket, 'TCP_KEEPCNT'): + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, keepalive_probes) + + +def is_port_in_use(port, host='0.0.0.0'): # nosec + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + try: + s.bind((host, port)) + except OSError as e: + if e.errno == 98: # Address already in use + return True + else: + raise + return False + + +def run_server(self, host='0.0.0.0', port=9440): # nosec + """ + Start the web server by creating and binding a socket on the specified IP and port. + + This method initializes the web server, optionally setting up SSL if the required + certificate and key files are found. The server listens for incoming connections + and handles them in separate threads. + + Args: + host (str): The IP address to bind the server to. Defaults to '0.0.0.0'. + port (int): The port number to bind the server to. Defaults to 9440. + + Steps: + 1. Logs the server start message. + 2. Uses configured IP and port if available. + 3. Creates a socket for the server. + 4. Checks for SSL certificates and sets up SSL context if available. + 5. Sets socket options and binds it to the specified host and port. + 6. Sets the socket to listen for incoming connections. + 7. Logs the status message indicating whether SSL is enabled. + 8. Starts the server loop to accept and handle client connections. + + Exceptions: + Exception: Logs any errors encountered during the server setup and startup process. + """ + + self.logging( "Log", f"WebUI - server starting on {host} {port}") + + # if is_port_in_use(port, host): + # self.logging( "Error", f"WebUI cannot start, Port {port} is already in use!!!") + # return + + try: + # Set up the server + if self.httpPort: + port = int(self.httpPort) + if self.httpIp: + host = self.httpIp + + self.logging( "Log", "++ WebUI - create socket") + self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # Check certificate and key + server_certificate = self.pluginconf.pluginConf.get("SSLCertificate") or os.path.join(self.homedirectory, "server.crt") + server_private_key = self.pluginconf.pluginConf.get("SSLPrivateKey") or os.path.join(self.homedirectory, "server.key") + self.logging( "Log", f"++ WebUI - SSL Certificate {server_certificate}") + self.logging( "Log", f"++ WebUI - SSL Private key {server_private_key}") + + context = check_cert_and_key(self, server_certificate, server_private_key) + + if context: + self.server = context.wrap_socket( self.server, server_side=True, ) + + self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + set_keepalive(self.server) + + self.logging( "Log", f"++ WebUI - bin socket on {host}:{port}") + self.server.bind((host, port)) + self.server.listen(5) + self.server.settimeout(10) + + if context: + self.logging("Status", f"WebUI Server started on SSL https://{host}:{port}") + else: + self.logging("Status", f"WebUI Server started on {host}:{port}") + + server_loop(self, ) + + self.logging( "Debug", "webui_thread - ended") + + except Exception as error: + self.logging( "Error", f"webui_thread - error in run_server {host} {port}") + self.logging( "Error", f" {error}") + self.logging( "Error", f" {str(traceback.format_exc())}") + + +def server_loop(self, ): + """ + Main server loop for handling incoming client connections. + + This method runs the main server loop that accepts incoming client connections, + starts a new thread to handle each client, and manages exceptions and errors + that occur during the process. The server continues to run as long as the `self.running` + attribute is set to True. + + The method performs the following tasks: + 1. Sets the `self.running` attribute to True to start the server loop. + 2. Accepts incoming client connections using `self.server.accept()`. + 3. Logs the accepted connection and starts a new thread for each client using the `handle_client` method. + 4. Appends each client thread to `self.client_threads` for tracking. + 5. Handles `socket.timeout` exceptions by continuing the loop. + 6. Handles `ssl.SSLError` exceptions by logging an error message and continuing the loop. + 7. Handles generic exceptions by logging an error message and breaking the loop. + 8. On termination, calls `close_all_clients` to close all client connections and shuts down the server socket. + + Exceptions: + socket.timeout: Logs a debug message and continues the loop. + ssl.SSLError: Logs an SSL error message and continues the loop. + Exception: Logs a generic error message and breaks the loop. + + """ + + try: + self.running = True + while self.running: + try: + client_socket, client_addr = self.server.accept() + + set_keepalive(client_socket) + + self.logging("Debug", f"Accepted connection from {client_addr} {client_socket}") + client_thread = threading.Thread(target=handle_client, args=(self, client_socket, client_addr)) + client_thread.daemon = True + client_thread.start() + self.client_threads.append(client_thread) + + except (socket.timeout, TimeoutError): + self.logging("Debug", "server_loop timeout") + continue + + except ssl.SSLError as e: + self.logging("Error", f"server_loop - SSL Error {e}, make sure to use https !!!") + continue + + except (ConnectionError, OSError) as e: + self.logging("Debug", f"server_loop - Socket error {e}") + continue + + except Exception as e: + self.logging("Error", f"server_loop - Unexpected error: {e}") + break + finally: + close_all_clients(self) + self.server.close() + self.logging("Debug", "Server shut down") + + +def decode_http_data(self, method, path, headers, body): + return { + "Verb": method, + "URL": path, + "Headers": headers, + "Data": body + } + + +def onConnect(self, Connection, Status, Description): + + self.logging("Error", "Connection: %s, description: %s onConnect for WebUI deprecated" % (Connection, Description)) + + +def onDisconnect(self, Connection): + + self.logging("Error", "onDisconnect %s on WebUI deprecated" % (Connection)) def onStop(self): # Make sure that all remaining open connections are closed - self.logging("Debug", "onStop()") - - # Search for Protocol - for connection in self.httpServerConns: - self.logging("Log", "Closing %s" % connection) - self.httpServerConns[connection.Name].close() + + self.running = False - for connection in self.httpsServerConns: - self.logging("Log", "Closing %s" % connection) - self.httpServerConns[connection.Name].close() + for client_thread in self.client_threads: + client_thread.join() + + self.server_thread.join() + self.logging("Status", "WebUI shutdown completed") + diff --git a/Classes/WebServer/dispatcher.py b/Classes/WebServer/dispatcher.py index fb674a1e7..f25b274a2 100644 --- a/Classes/WebServer/dispatcher.py +++ b/Classes/WebServer/dispatcher.py @@ -136,7 +136,8 @@ def execute_rest_command(self, verb, data, version, command, parameters): response = REST_COMMANDS[command]["functionv2"](verb, data, parameters) return response - + + def prepare_help_response(self): response = prepResponseMessage(self, setupHeadersResponse()) _data = {} @@ -154,6 +155,7 @@ def prepare_error_message(self, command): response["Data"] = "Unknown REST command: %s" % command response["Headers"]["Content-Type"] = "text/plain; charset=utf-8" return response - + + def do_nothing(self, verb, data, parameters): pass diff --git a/Classes/WebServer/headerResponse.py b/Classes/WebServer/headerResponse.py index aa184a677..188a84fa4 100644 --- a/Classes/WebServer/headerResponse.py +++ b/Classes/WebServer/headerResponse.py @@ -28,8 +28,7 @@ def prepResponseMessage(self, _response): def setupHeadersResponse(cookie=None): - _response = {} - _response["Headers"] = {} + _response = {"Headers": {}} _response["Headers"]["Server"] = "Domoticz" _response["Headers"]["User-Agent"] = "Plugin-Zigbee4Domoticz/v1" diff --git a/Classes/WebServer/onMessage.py b/Classes/WebServer/onMessage.py index e9178b804..fba47f4b5 100644 --- a/Classes/WebServer/onMessage.py +++ b/Classes/WebServer/onMessage.py @@ -14,7 +14,7 @@ from Classes.WebServer.headerResponse import (prepResponseMessage, setupHeadersResponse) -from Classes.WebServer.tools import MAX_KB_TO_SEND, DumpHTTPResponseToLog +from Classes.WebServer.tools import MAX_BLOCK_SIZE, DumpHTTPResponseToLog from Modules.domoticzAbstractLayer import (domoticz_error_api, domoticz_log_api, domoticz_status_api) @@ -57,11 +57,19 @@ def onMessage(self, Connection, Data): if handle_rest_api(self, Connection, Data, parsed_query): return - if handle_download( parsed_query, parsed_url): - return + self.logging("Debug", f"Download: {is_download( parsed_query, parsed_url)}") + if is_download( parsed_query, parsed_url): + # we have to serve a file for download purposes, let's remove '/download' to get the filename to access + webFilename = parsed_url.path[len('/download'):] + + else: + # Most likely a file from the wwww/ to be served + webFilename = get_web_filename(self, url, parsed_query, parsed_url) + + self.logging("Debug", f"Downloading: {webFilename}") - webFilename = get_web_filename(self, url, parsed_query, parsed_url) if not os.path.isfile(webFilename): + self.logging("Debug", "Redirect to index.html") webFilename = redirect_to_index_html(self) response_headers = prepare_response_headers(self,cookie) @@ -98,7 +106,7 @@ def handle_rest_api(self, Connection, Data, parsed_query): return True -def handle_download( parsed_query, parsed_url): +def is_download( parsed_query, parsed_url): return parsed_query[0] == 'download' @@ -230,7 +238,7 @@ def get_range_and_send(self, Connection, webFilename, Data, _response): messageFile = open(webFilename, mode="rb") messageFile.seek(fileStartPosition) - fileContent = messageFile.read(MAX_KB_TO_SEND) + fileContent = messageFile.read(MAX_BLOCK_SIZE) self.logging( "Debug", @@ -238,7 +246,7 @@ def get_range_and_send(self, Connection, webFilename, Data, _response): ) _response["Status"] = "200 OK" - if len(fileContent) == MAX_KB_TO_SEND: + if len(fileContent) == MAX_BLOCK_SIZE: _response["Status"] = "206 Partial Content" _response["Headers"]["Content-Range"] = f"bytes {fileStartPosition}-{messageFile.tell()}/{messageFileSize}" diff --git a/Classes/WebServer/rest_Provisioning.py b/Classes/WebServer/rest_Provisioning.py index a47e8072b..30dbd861c 100644 --- a/Classes/WebServer/rest_Provisioning.py +++ b/Classes/WebServer/rest_Provisioning.py @@ -35,12 +35,12 @@ def rest_new_hrdwr(self, verb, data, parameters): data = {} if len(parameters) != 1: domoticz_error_api("rest_new_hrdwr - unexpected parameter %s " % parameters) - _response["Data"] = {"unexpected parameter %s " % parameters} + _response["Data"] = { "BE_Error": "unexpected parameter %s " % parameters} return _response if parameters[0] not in ("enable", "cancel", "disable"): domoticz_error_api("rest_new_hrdwr - unexpected parameter %s " % parameters[0]) - _response["Data"] = {"unexpected parameter %s " % parameters[0]} + _response["Data"] = { "BE_Error": "unexpected parameter %s " % parameters[0]} return _response if parameters[0] == "enable": @@ -55,7 +55,7 @@ def rest_new_hrdwr(self, verb, data, parameters): if self.permitTojoin["Duration"] != 255 and self.pluginParameters["Mode2"] != "None": ZigatePermitToJoin(self, (4 * 60)) - _response["Data"] = {"start pairing mode at %s " % int(time())} + _response["Data"] = { "BE_Start": "start pairing mode at %s " % int(time())} return _response if parameters[0] in ("cancel", "disable"): @@ -71,7 +71,7 @@ def rest_new_hrdwr(self, verb, data, parameters): if not (self.permitTojoin["Duration"] == 255 or self.pluginParameters["Mode2"] == "None"): ZigatePermitToJoin(self, 0) - _response["Data"] = {"stop pairing mode at %s " % int(time())} + _response["Data"] = {"BE_Stop": "stop pairing mode at %s " % int(time())} return _response @@ -248,7 +248,7 @@ def rest_full_reprovisionning(self, verb, data, parameters): if "IEEE" not in data and "NWKID" not in data: domoticz_error_api("rest_full_reprovisionning - unexpected parameter %s " % parameters) - _response["Data"] = {"unexpected parameter %s " % parameters} + _response["Data"] = { "BE_status": "unexpected parameter %s " % parameters} return _response if "IEEE" in data: @@ -257,13 +257,13 @@ def rest_full_reprovisionning(self, verb, data, parameters): domoticz_error_api("rest_full_reprovisionning - Unknown device %s " % key) return _response nwkid = self.IEEE2NWK[key] - _response["Data"] = {"IEEE %s set to Provisioning Requested at %s" % (key, int(time()))} + _response["Data"] = { "BE_status": "IEEE %s set to Provisioning Requested at %s" % (key, int(time()))} else: nwkid = data["NWKID"] if nwkid not in self.ListOfDevices: domoticz_error_api("rest_full_reprovisionning - Unknown device %s " % nwkid) return _response - _response["Data"] = {"NwkId %s set to Provisioning Requested at %s" % (nwkid, int(time()))} + _response["Data"] = {"BE_status": "NwkId %s set to Provisioning Requested at %s" % (nwkid, int(time()))} if "Bind" in self.ListOfDevices[nwkid]: del self.ListOfDevices[nwkid]["Bind"] diff --git a/Classes/WebServer/rest_recreateWidget.py b/Classes/WebServer/rest_recreateWidget.py index 29c8888af..51ddfe3e1 100644 --- a/Classes/WebServer/rest_recreateWidget.py +++ b/Classes/WebServer/rest_recreateWidget.py @@ -4,6 +4,7 @@ # Author: zaraki673 & pipiche38 # from time import time +import json from Classes.WebServer.headerResponse import (prepResponseMessage, setupHeadersResponse) @@ -31,7 +32,8 @@ def rest_recreate_widgets(self, verb, data, parameters): if "IEEE" not in data and "NWKID" not in data: domoticz_error_api("rest_recreate_widgets - unexpected parameter %s " % parameters) - _response["Data"] = {"unexpected parameter %s " % parameters} + _response["Data"] = json.dumps({"Status": "Error", "Description": "unexpected parameter %s " % parameters}) + return _response if "IEEE" in data: @@ -40,13 +42,13 @@ def rest_recreate_widgets(self, verb, data, parameters): domoticz_error_api("rest_recreate_widgets - Unknown device %s " % key) return _response nwkid = self.IEEE2NWK[key] - _response["Data"] = {"IEEE %s set to Provisioning Requested at %s" % (key, int(time()))} + _response["Data"] = json.dumps({"Status": "Ok", "Status": "IEEE %s set to Provisioning Requested at %s" % (key, int(time()))}) else: nwkid = data["NWKID"] if nwkid not in self.ListOfDevices: domoticz_error_api("rest_recreate_widgets - Unknown device %s " % nwkid) return _response - _response["Data"] = {"NwkId %s set to Provisioning Requested at %s" % (nwkid, int(time()))} + _response["Data"] = json.dumps({"Status": "Ok", "Status": "NwkId %s set to Provisioning Requested at %s" % (nwkid, int(time()))}) over_write_type_from_deviceconf( self, self.Devices, nwkid) self.ListOfDevices[nwkid]["Status"] = "CreateDB" diff --git a/Classes/WebServer/sendresponse.py b/Classes/WebServer/sendresponse.py index 5d3079375..8ea07e541 100644 --- a/Classes/WebServer/sendresponse.py +++ b/Classes/WebServer/sendresponse.py @@ -4,94 +4,174 @@ # Author: zaraki673 & pipiche38 # -import zlib import gzip +import json +import zlib + +from Classes.WebServer.tools import MAX_BLOCK_SIZE, DumpHTTPResponseToLog + +http_status_codes = { + 100: "HTTP/1.1 100 Continue\r\n", + 101: "HTTP/1.1 101 Switching Protocols\r\n", + 200: "HTTP/1.1 200 OK\r\n", + 201: "HTTP/1.1 201 Created\r\n", + 202: "HTTP/1.1 202 Accepted\r\n", + 204: "HTTP/1.1 204 No Content\r\n", + 301: "HTTP/1.1 301 Moved Permanently\r\n", + 302: "HTTP/1.1 302 Found\r\n", + 304: "HTTP/1.1 304 Not Modified\r\n", + 400: "HTTP/1.1 400 Bad Request\r\n", + 401: "HTTP/1.1 401 Unauthorized\r\n", + 403: "HTTP/1.1 403 Forbidden\r\n", + 404: "HTTP/1.1 404 Not Found\r\n", + 405: "HTTP/1.1 405 Method Not Allowed\r\n", + 500: "HTTP/1.1 500 Internal Server Error\r\n", + 501: "HTTP/1.1 501 Not Implemented\r\n", + 503: "HTTP/1.1 503 Service Unavailable\r\n", + 505: "HTTP/1.1 505 HTTP Version Not Supported\r\n" +} + +HTTP_HEADERS = { + "Server", + "User-Agent", + "Access-Control-Allow-Headers", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Origin", + "Referrer-Policy", + "Cookie", + "Connection", + "Cache-Control", + "Pragma", + "Expires", + "Accept", + "Last-Modified", + "Content-Type", + "Content-Encoding", +} + +def send_by_chunk(self, socket, http_response, response_body): + """ send and chunk the response_body already bytes encoded """ + + if not response_body: + return + + # send the HTTP headers + socket.sendall( http_response.encode('utf-8')) + + for i in range(0, len(response_body), MAX_BLOCK_SIZE): + chunck_data = response_body[ i : i + MAX_BLOCK_SIZE] + + socket.sendall(f"{len(chunck_data):X}\r\n".encode("utf-8")) + socket.sendall(chunck_data) + socket.sendall(b"\r\n") + + self.logging("Debug", "Sending Chunk: %s out of %s" % (i, len(response_body) / MAX_BLOCK_SIZE)) + + # Closing Chunk + socket.sendall(b"0\r\n\r\n") + + +def send_http_message( self, socket, http_response, response_body, chunked=False): + if chunked: + send_by_chunk(self, socket, http_response, response_body) + else: + socket.sendall( http_response.encode('utf-8') + response_body ) + + +def encode_body_to_bytes(response): + """Convert data payload into an HTTP response body encoded bytes.""" + if "Data" not in response: + return b'' + + response_data = response["Data"] + + if isinstance(response_data, dict): + return json.dumps(response_data).encode('utf-8') + + elif isinstance(response_data, bytes): + # If response_data is already bytes, return it as is + return response_data -from Classes.WebServer.tools import MAX_KB_TO_SEND, DumpHTTPResponseToLog + elif response_data is not None: + return str(response_data).encode('utf-8') + # Default to an empty response if no valid Data is present + return b'' -def sendResponse(self, Connection, Response, AcceptEncoding=None): + +def prepare_http_response( self, response_dict, gziped=False, deflated=False , chunked=False): + # Prepare body (data converted to byte) + response_body = encode_body_to_bytes( response_dict ) + + if 'Status' in response_dict: + status = response_dict[ "Status"].split(' ') + status_code = 500 if len(status) < 1 else int(status[0]) + if status_code in http_status_codes: + http_response = http_status_codes[ status_code ] + + if 'Headers' in response_dict: + headers = response_dict['Headers'] + for x in HTTP_HEADERS: + if x in headers and headers[x]: + http_response += f"{x}: {headers[x]}\r\n" + + # Determine if Compression, Deflate or Chunk to be used. + orig_size = len(response_body) + + # prefer gzip for better compatibility, consistent behavior, and improved compression. If the two are accepted by the client + if gziped: + self.logging("Debug", "Compressing - gzip") + http_response += "Content-Encoding: gzip\r\n" + response_body = gzip.compress(response_body) + self.logging( "Debug", "Compression from %s to %s (%s %%)" % (orig_size, len(response_body), int(100 - (len(response_body) / orig_size) * 100)), ) + + elif deflated: + self.logging("Debug", "Compressing - deflate") + http_response += "Content-Encoding: deflate\r\n" + zlib_compress = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 2) + response_body = zlib_compress.compress(response_body) + response_body += zlib_compress.flush() + self.logging( "Debug", "Compression from %s to %s (%s %%)" % (orig_size, len(response_body), int(100 - (len(response_body) / orig_size) * 100)), ) + + # Content-Length set to the body sent. If compressed this has to be the + http_response += f"Content-Length: {len(response_body)}\r\n" + + if chunked: + http_response += "Transfer-Encoding: chunked\r\n" + + http_response += "\r\n" + self.logging("Debug", f"{http_response}") + + return http_response, response_body + + +def sendResponse(self, client_socket, Response, AcceptEncoding=None): + + # No data if "Data" not in Response: - #DumpHTTPResponseToLog(Response) - Connection.Send(Response) + http_response, response_body = prepare_http_response( self, Response ) + send_http_message( self, client_socket, http_response, response_body) if not self.pluginconf.pluginConf["enableKeepalive"]: - Connection.Disconnect() + client_socket.close() return + # Empty Data if Response["Data"] is None: - #DumpHTTPResponseToLog(Response) - Connection.Send(Response) + http_response, response_body = prepare_http_response( self, Response ) + send_http_message( self, client_socket, http_response, response_body) if not self.pluginconf.pluginConf["enableKeepalive"]: - Connection.Disconnect() + client_socket.close() return - #self.logging("Debug", "Sending Response to : %s" % (Connection.Name)) - # Compression - allowgzip = self.pluginconf.pluginConf["enableGzip"] - allowdeflate = self.pluginconf.pluginConf["enableDeflate"] - - if (allowgzip or allowdeflate) and "Data" in Response and AcceptEncoding: - #self.logging( "Debug", "sendResponse - Accept-Encoding: %s, Chunk: %s, Deflate: %s , Gzip: %s" % (AcceptEncoding, self.pluginconf.pluginConf["enableChunk"], allowdeflate, allowgzip), ) - if len(Response["Data"]) > MAX_KB_TO_SEND: - orig_size = len(Response["Data"]) - if allowdeflate and AcceptEncoding.find("deflate") != -1: - #self.logging("Debug", "Compressing - deflate") - zlib_compress = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 2) - deflated = zlib_compress.compress(Response["Data"]) - deflated += zlib_compress.flush() - Response["Headers"]["Content-Encoding"] = "deflate" - Response["Data"] = deflated - - elif allowgzip and AcceptEncoding.find("gzip") != -1: - #self.logging("Debug", "Compressing - gzip") - Response["Data"] = gzip.compress(Response["Data"]) - Response["Headers"]["Content-Encoding"] = "gzip" - - #self.logging( "Debug", "Compression from %s to %s (%s %%)" % (orig_size, len(Response["Data"]), int(100 - (len(Response["Data"]) / orig_size) * 100)), ) - - # Chunking, Follow the Domoticz Python Plugin Framework - - if self.pluginconf.pluginConf["enableChunk"] and len(Response["Data"]) > MAX_KB_TO_SEND: - idx = 0 - HTTPchunk = {} - HTTPchunk["Status"] = Response["Status"] - HTTPchunk["Chunk"] = True - HTTPchunk["Headers"] = {} - HTTPchunk["Headers"] = dict(Response["Headers"]) - HTTPchunk["Data"] = Response["Data"][0:MAX_KB_TO_SEND] - #self.logging("Debug", "Sending: %s out of %s" % (idx, len((Response["Data"])))) - - # Firs Chunk - #DumpHTTPResponseToLog(HTTPchunk) - Connection.Send(HTTPchunk) - - idx = MAX_KB_TO_SEND - while idx != -1: - tosend = {} - tosend["Chunk"] = True - if idx + MAX_KB_TO_SEND < len(Response["Data"]): - # we have to send one chunk and then continue - tosend["Data"] = Response["Data"][idx : idx + MAX_KB_TO_SEND] - idx += MAX_KB_TO_SEND - else: - # Last Chunk with Data - tosend["Data"] = Response["Data"][idx:] - idx = -1 - - #self.logging("Debug", "Sending Chunk: %s out of %s" % (idx, len((Response["Data"])))) - Connection.Send(tosend) - - # Closing Chunk - tosend = {} - tosend["Chunk"] = True - Connection.Send(tosend) - if not self.pluginconf.pluginConf["enableKeepalive"]: - Connection.Disconnect() - else: - # Response['Headers']['Content-Length'] = len( Response['Data'] ) - #DumpHTTPResponseToLog(Response) - Connection.Send(Response) - if not self.pluginconf.pluginConf["enableKeepalive"]: - Connection.Disconnect() + request_gzip = self.pluginconf.pluginConf["enableGzip"] and AcceptEncoding and (AcceptEncoding.find("gzip") != -1) + request_deflate = self.pluginconf.pluginConf["enableDeflate"] and AcceptEncoding and (AcceptEncoding.find("deflate") != -1) + request_chunked = self.pluginconf.pluginConf["enableChunk"] and len(Response["Data"]) > MAX_BLOCK_SIZE + + self.logging("Debug", f"request_gzip {request_gzip} - request_deflate {request_deflate} request_chunked {request_chunked}") + http_response, response_body = prepare_http_response( self, Response, request_gzip, request_deflate, request_chunked ) + send_http_message( self, client_socket, http_response, response_body ,request_chunked) + + if not self.pluginconf.pluginConf["enableKeepalive"]: + client_socket.close() diff --git a/Classes/WebServer/tools.py b/Classes/WebServer/tools.py index c7a8d4f3d..032a767c9 100644 --- a/Classes/WebServer/tools.py +++ b/Classes/WebServer/tools.py @@ -8,7 +8,7 @@ domoticz_log_api, domoticz_status_api) -MAX_KB_TO_SEND = 8 * 1024 # Chunk size +MAX_BLOCK_SIZE = 8 * 1024 # Chunk size DEBUG_HTTP = False diff --git a/Classes/ZigpyTransport/zigpyThread.py b/Classes/ZigpyTransport/zigpyThread.py index 70ab8d91b..8989b6aca 100644 --- a/Classes/ZigpyTransport/zigpyThread.py +++ b/Classes/ZigpyTransport/zigpyThread.py @@ -580,7 +580,7 @@ async def process_raw_command(self, data, AckIsDisable=False, Sqn=None): self.log.logging("TransportZigpy", "Debug", f"process_raw_command: extended_timeout {extended_timeout}") delay = data.get("Delay", None) - self.log.logging("TransportZigpy", "Debug", f"process_raw_command: process_raw_command ready to request Function: {Function} NwkId: {NwkId}/{dEp} Cluster: {Cluster} Seq: {sequence} Payload: {payload.hex()} AddrMode: {addressmode} EnableAck: {not AckIsDisable}, Sqn: {Sqn}, Delay: {delay}, Extended_TO: {extended_timeout}") + self.log.logging("TransportZigpy", "Debug", f"process_raw_command: process_raw_command ready to request Function: {Function} NwkId: {NwkId}/{dEp} Cluster: {Cluster} Seq: {sequence} Payload: {payload.hex()} AddrMode: {addressmode} AckIsDisable: {AckIsDisable} EnableAck: {not AckIsDisable}, Sqn: {Sqn}, Delay: {delay}, Extended_TO: {extended_timeout}") destination, transport_needs = _get_destination(self, NwkId, addressmode, Profile, Cluster, sEp, dEp, sequence, payload) @@ -756,7 +756,7 @@ def check_transport_readiness(self): def measure_execution_time(func): - async def wrapper(self, Function, destination, Profile, Cluster, sEp, dEp, sequence, payload, ack_is_disable=False, use_ieee=False, delay=None, extended_timeout=False): + async def wrapper(self, Function, destination, Profile, Cluster, sEp, dEp, sequence, payload, ack_is_disable, use_ieee, delay, extended_timeout): t_start = None if self.pluginconf.pluginConf.get("ZigpyReactTime", False): t_start = int(1000 * time.time()) @@ -769,7 +769,7 @@ async def wrapper(self, Function, destination, Profile, Cluster, sEp, dEp, seque t_end = int(1000 * time.time()) t_elapse = t_end - t_start self.statistics.add_timing_zigpy(t_elapse) - self.log.logging("TransportZigpy", "Log", f"| (transport_request) | {t_elapse} | {Function} | {destination.nwk} | {destination.ieee} | {destination.model} | {destination.manufacturer_id} | {destination.is_initialized} | {destination.rssi} | {destination.lqi} |") + self.log.logging("TransportZigpy", "Log", f"| (transport_request) | {t_elapse} | {Function} | {sequence} | {ack_is_disable} | {destination.nwk} | {destination.ieee} | {destination.model} | {destination.manufacturer_id} | {destination.is_initialized} | {destination.rssi} | {destination.lqi} |") return wrapper @@ -815,15 +815,16 @@ async def transport_request(self, Function, destination, Profile, Cluster, sEp, async def _send_and_retry(self, Function, destination, Profile, Cluster, _nwkid, sEp, dEp, sequence, payload, use_ieee, _ieee, ack_is_disable, extended_timeout): - max_retry = MAX_ATTEMPS_REQUEST if self.pluginconf.pluginConf["PluginRetrys"] else 1 + max_retry = MAX_ATTEMPS_REQUEST if self.pluginconf.pluginConf["PluginRetrys"] else 1 + for attempt in range(1, (max_retry + 1)): try: - self.log.logging("TransportZigpy", "Debug", f"_send_and_retry: {_ieee} {Profile} {Cluster} - Expect_Reply: {ack_is_disable} extended_timeout: {extended_timeout} Attempts: {attempt}/{max_retry}") - result, msg = await self.app.request(destination, Profile, Cluster, sEp, dEp, sequence, payload, expect_reply=not ack_is_disable, use_ieee=use_ieee, extended_timeout=extended_timeout) + self.log.logging("TransportZigpy", "Debug", f"_send_and_retry: {_ieee} {Profile:X} {Cluster:X} - AckIsDisable: {ack_is_disable} extended_timeout: {extended_timeout} Attempts: {attempt}/{max_retry}") + result, _ = await zigpy_request(self, destination, Profile, Cluster, sEp, dEp, sequence, payload, ack_is_disable=ack_is_disable, use_ieee=use_ieee, extended_timeout=extended_timeout) except (asyncio.exceptions.TimeoutError, asyncio.exceptions.CancelledError, AttributeError, DeliveryError) as e: - error_log_message = f"{Function} {_ieee}/0x{_nwkid} 0x{Profile} 0x{Cluster}:16 Ack: {ack_is_disable} RETRY: {attempt}/{max_retry} ({e})" + error_log_message = f"Warning while submitting - {Function} {_ieee}/0x{_nwkid} 0x{Profile:X} 0x{Cluster:X} payload: {payload} AckIsDisable: {ack_is_disable} Retry: {attempt}/{max_retry} with exception ({e})" self.log.logging("TransportZigpy", "Log", error_log_message) if await _retry_or_not(self, attempt, max_retry, Function, sequence, ack_is_disable, _ieee, _nwkid, destination, e): @@ -835,12 +836,108 @@ async def _send_and_retry(self, Function, destination, Profile, Cluster, _nwkid, self.statistics._ackKO += 1 break + except Exception as error: + # Any other exception + error_log_message = f"_send_and_retry - Unexpected Exception - {Function} {_ieee}/0x{_nwkid} 0x{Profile:X} 0x{Cluster:X} payload: {payload} AckIsDisable: {ack_is_disable} RETRY: {attempt}/{max_retry} ({error})" + self.log.logging("TransportZigpy", "Error", error_log_message) + result = 0xB6 + else: # Success handle_transport_result(self, Function, sequence, result, ack_is_disable, _ieee, _nwkid, destination.lqi) - self.log.logging("TransportZigpy", "Debug", f"transport_request: result: {result}") + self.log.logging("TransportZigpy", "Debug", f"_send_and_retry: result: {result}") break + +async def zigpy_request( self, device: zigpy.device.Device, profile: t.uint16_t, cluster: t.uint16_t, src_ep: t.uint8_t, dst_ep: t.uint8_t, sequence: t.uint8_t, data: bytes, *, ack_is_disable: bool = True, use_ieee: bool = False, extended_timeout: bool = False, ) -> tuple[zigpy.zcl.foundation.Status, str]: + """Submit and send data out as an unicast transmission.""" + + self.log.logging( + "TransportZigpy", + "Debug", + f"zigpy_request: " + f"zigpy_request called with: device={device}, profile={profile}, cluster={cluster}, " + f"src_ep={src_ep}, dst_ep={dst_ep}, sequence={sequence}, data={data}, " + f"ack_is_disable={ack_is_disable}, use_ieee={use_ieee}, extended_timeout={extended_timeout}" + ) + if use_ieee: + src = t.AddrModeAddress( addr_mode=t.AddrMode.IEEE, address=self.app.state.node_info.ieee ) + dst = t.AddrModeAddress(addr_mode=t.AddrMode.IEEE, address=device.ieee) + else: + src = t.AddrModeAddress( addr_mode=t.AddrMode.NWK, address=self.app.state.node_info.nwk ) + dst = t.AddrModeAddress(addr_mode=t.AddrMode.NWK, address=device.nwk) + + if self.app.config[zigpy.config.CONF_SOURCE_ROUTING]: + source_route = self.app.build_source_route_to(dest=device) + else: + source_route = None + + tx_options = t.TransmitOptions.NONE + + if not ack_is_disable: + tx_options |= t.TransmitOptions.ACK + + await self.app.send_packet( + t.ZigbeePacket( + src=src, + src_ep=src_ep, + dst=dst, + dst_ep=dst_ep, + tsn=sequence, + profile_id=profile, + cluster_id=cluster, + data=t.SerializableBytes(data), + extended_timeout=extended_timeout, + source_route=source_route, + tx_options=tx_options, + ) + ) + + return (zigpy.zcl.foundation.Status.SUCCESS, "") + + +async def zigpy_mrequest( self, group_id: t.uint16_t, profile: t.uint8_t, cluster: t.uint16_t, src_ep: t.uint8_t, sequence: t.uint8_t, data: bytes, *, hops: int = 0, non_member_radius: int = 3,): + """Submit and send data out as a multicast transmission.""" + + await self.app.send_packet( + t.ZigbeePacket( + src=t.AddrModeAddress( addr_mode=t.AddrMode.NWK, address=self.state.node_info.nwk ), + src_ep=src_ep, + dst=t.AddrModeAddress(addr_mode=t.AddrMode.Group, address=group_id), + tsn=sequence, + profile_id=profile, + cluster_id=cluster, + data=t.SerializableBytes(data), + tx_options=t.TransmitOptions.NONE, + radius=hops, + non_member_radius=non_member_radius, + ) + ) + + return (zigpy.zcl.foundation.Status.SUCCESS, "") + + +async def zigpy_broadcast( self, profile: t.uint16_t, cluster: t.uint16_t, src_ep: t.uint8_t, dst_ep: t.uint8_t, grpid: t.uint16_t, radius: int, sequence: t.uint8_t, data: bytes, broadcast_address: t.BroadcastAddress = t.BroadcastAddress.RX_ON_WHEN_IDLE, ) -> tuple[zigpy.zcl.foundation.Status, str]: + """Submit and send data out as an unicast transmission.""" + + await self.app.send_packet( + t.ZigbeePacket( + src=t.AddrModeAddress( addr_mode=t.AddrMode.NWK, address=self.state.node_info.nwk ), + src_ep=src_ep, + dst=t.AddrModeAddress( addr_mode=t.AddrMode.Broadcast, address=broadcast_address ), + dst_ep=dst_ep, + tsn=sequence, + profile_id=profile, + cluster_id=cluster, + data=t.SerializableBytes(data), + tx_options=t.TransmitOptions.NONE, + radius=radius, + ) + ) + + return (zigpy.zcl.foundation.Status.SUCCESS, "") + + async def _retry_or_not(self, attempt, max_retry, Function, sequence,ack_is_disable, _ieee, _nwkid, destination , e): if attempt < max_retry: # Slow down the throughput when too many commands. Try not to overload the coordinators @@ -856,8 +953,12 @@ async def _retry_or_not(self, attempt, max_retry, Function, sequence,ack_is_disa def handle_transport_result(self, Function, sequence, result, ack_is_disable, _ieee, _nwkid, lqi): - self.log.logging("TransportZigpy", "Debug", f"handle_transport_result - {Function} - {_nwkid} - Ack: {ack_is_disable} Result: {result}") - #if not ack_is_disable: + self.log.logging("TransportZigpy", "Debug", f"handle_transport_result - {Function} - {_nwkid} - AckIsDisable: {ack_is_disable} Result: {result}") + if ack_is_disable: + # As Ack is disable, we cannot conclude that the target device is in trouble. + # this could be the coordinator itself, or the next hop. + return + push_APS_ACK_NACKto_plugin(self, _nwkid, result, lqi) if result == 0x00 and _ieee in self._currently_not_reachable: diff --git a/Conf/ZclDefinitions/0001.json b/Conf/ZclDefinitions/0001.json index 917e0e9f8..df19a9f47 100644 --- a/Conf/ZclDefinitions/0001.json +++ b/Conf/ZclDefinitions/0001.json @@ -78,7 +78,7 @@ "Mandatory": false, "DomoClusterType": "Voltage", "EvalExp": "round(int(value) / 10, 1)", - "ActionList": [ "check_store_raw_value", "upd_domo_device", "update_battery"] + "ActionList": [ "check_store_raw_value", "upd_domo_device", "update_battery", "update_battery_voltage"] }, "0021": { "Enabled": true, @@ -89,7 +89,7 @@ "Acc": "RP" , "Default": "0", "Mandatory": false, - "ActionList": [ "check_store_value", "update_battery"] + "ActionList": [ "check_store_value", "upd_domo_device", "update_battery", "update_battery_percentage"] }, "0030": { "Enabled": true, "Name": "BatteryManufacturer", "DataType": "41", "ActionList": [ "check_store_value"] }, diff --git a/DevicesModules/custom_sunricher.py b/DevicesModules/custom_sunricher.py new file mode 100644 index 000000000..d5a8fee48 --- /dev/null +++ b/DevicesModules/custom_sunricher.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Implementation of Zigbee for Domoticz plugin. +# +# This file is part of Zigbee for Domoticz plugin. https://github.com/zigbeefordomoticz/Domoticz-Zigbee +# (C) 2015-2024 +# +# Initial authors: zaraki673 & pipiche38 +# +# SPDX-License-Identifier: GPL-3.0 license + +from Modules.basicOutputs import read_attribute, write_attribute +from Modules.zigateConsts import ZIGATE_EP + +SUNRICHER_MAUFACTURER_NAME = "SUNRICHER" +SUNRICHER_MANUFACTURER_ID = "1224" + +OCCUPANCY_ENDPOINT = "01" +OCCUPANCY_CLUSTERID = "0406" +SUNRICHER_PIR_SENSOR_SENSITIVITY = "1000" +SUNRICHER_MOTION_DETECTION_BLIND_TIME = "1001" +SUNRICHER_MOTION_DETECTION_PULSE_COUNTER = "1002" +SUNRICHER_PIR_SENSOR_TRIGGER_TIME_INTERVAL = "1003" + +TEMPERATURE_ENDPOINT = "03" +TEMPERATURE_CLUSTERID = "0402" +SUNRICHER_TEMPERATURE_COMPENSATION = "1000" # Int8s + +HUMIDITY_ENDPOINT = "04" +HUMIDITY_CLUSTERID = "0405" +SUNRICHER_HUMIDITY_COMPENSATION = "1000" # Int8s + + + +def is_sunricher_device(self, nwkid): + return self.ListOfDevices[nwkid]["Manufacturer"] == SUNRICHER_MANUFACTURER_ID or self.ListOfDevices[nwkid]["Manufacturer Name"] == SUNRICHER_MAUFACTURER_NAME + + +def sunricher_pir_sensor_sensitivity(self, nwkid, sensitivity): + self.log.logging("Sunricher", "Debug", "sunricher_pir_sensor_sensitivity - Nwkid: %s Sensitivity: %s" % (nwkid, sensitivity)) + write_attribute(self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_PIR_SENSOR_SENSITIVITY, "30", "%02x" %sensitivity, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_PIR_SENSOR_SENSITIVITY, ackIsDisabled=False ) + + +def sunricher_motion_detection_blind_time(self, nwkid, blind_time): + self.log.logging("Sunricher", "Debug", "sunricher_motion_detection_blind_time - Nwkid: %s Blind Time: %s" %(nwkid, blind_time)) + write_attribute(self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_MOTION_DETECTION_BLIND_TIME, "20", "%02x" %blind_time, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_MOTION_DETECTION_BLIND_TIME, ackIsDisabled=False ) + + +def sunricher_motion_detection_pulse_counter(self, nwkid, pulse_setting): + self.log.logging("Sunricher", "Debug", "sunricher_motion_detection_pulse_counter - Nwkid: %s Pulse Setting: %s" %(nwkid, pulse_setting)) + write_attribute(self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_MOTION_DETECTION_PULSE_COUNTER, "30", "%02x" %pulse_setting, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_MOTION_DETECTION_PULSE_COUNTER, ackIsDisabled=False ) + + +def sunricher_pir_sensor_trigger_time_interval(self, nwkid, trigger_time_interval): + self.log.logging("Sunricher", "Debug", "sunricher_pir_sensor_trigger_time_interval - Nwkid: %s Trigger Time Interval: %s" %(nwkid, sunricher_pir_sensor_trigger_time_interval)) + write_attribute(self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_PIR_SENSOR_TRIGGER_TIME_INTERVAL, "30", "%02x" %trigger_time_interval, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, OCCUPANCY_ENDPOINT, OCCUPANCY_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_PIR_SENSOR_TRIGGER_TIME_INTERVAL, ackIsDisabled=False ) + + +def sunricher_temperature_compensation(self, nwkid, compensation): + self.log.logging("Sunricher", "Debug", "sunricher_temperature_compensation - Nwkid: %s compensation: %s" % (nwkid, compensation)) + if compensation < 0: + compensation = _two_complement( compensation ) + self.log.logging( "Sunricher", "Debug", "sunricher_temperature_compensation - 2 complement form of compensation offset on %s off %s" % (nwkid, compensation), ) + + write_attribute(self, nwkid, ZIGATE_EP, TEMPERATURE_ENDPOINT, TEMPERATURE_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_TEMPERATURE_COMPENSATION, "28", "%02x" %compensation, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, TEMPERATURE_ENDPOINT, TEMPERATURE_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_TEMPERATURE_COMPENSATION, ackIsDisabled=False ) + + +def sunricher_humidity_compensation(self, nwkid, compensation): + self.log.logging("Sunricher", "Debug", "sunricher_humidity_compensation - Nwkid: %s compensation: %s" % (nwkid, compensation)) + if compensation < 0: + compensation = _two_complement( compensation ) + self.log.logging( "Sunricher", "Debug", "sunricher_temperature_compensation - 2 complement form of compensation offset on %s off %s" % (nwkid, compensation), ) + + write_attribute(self, nwkid, ZIGATE_EP, HUMIDITY_ENDPOINT, HUMIDITY_CLUSTERID, SUNRICHER_MANUFACTURER_ID, "01", SUNRICHER_HUMIDITY_COMPENSATION, "28", "%02x" %compensation, ackIsDisabled=False) + read_attribute( self, nwkid, ZIGATE_EP, HUMIDITY_ENDPOINT, HUMIDITY_CLUSTERID, "00", "01", SUNRICHER_MANUFACTURER_ID, 0x01, SUNRICHER_HUMIDITY_COMPENSATION, ackIsDisabled=False ) + + +def _two_complement( negative_value ): + # in two’s complement form + return int(hex(-negative_value - pow(2, 32))[9:], 16) + + +SUNRICHER_DEVICE_PARAMETERS = { + "Sunricher_PIR_SENSITIVITY": sunricher_pir_sensor_sensitivity, + "Sunricher_MOTION_BLIND_TIME": sunricher_motion_detection_blind_time, + "Sunricher_MOTION_PULSE_COUNTER": sunricher_motion_detection_pulse_counter, + "Sunricher_PIR_TRIGGER_TIME_INTERVAL": sunricher_pir_sensor_trigger_time_interval, + "Sunricher_Temperature_Compensation": sunricher_temperature_compensation, + "Sunricher_Humidity_Compensation": sunricher_humidity_compensation +} diff --git a/Modules/batterieManagement.py b/Modules/batterieManagement.py index 30c9c77b3..62d12e38c 100644 --- a/Modules/batterieManagement.py +++ b/Modules/batterieManagement.py @@ -17,12 +17,21 @@ """ -from time import time +import time from Modules.domoTools import Update_Battery_Device from Modules.tools import get_deviceconf_parameter_value, voltage2batteryP +def get_float_value(device_data, keys): + value = device_data + for key in keys: + value = value.get(key, {}) + if value == {}: + return None + return float(value) + + def UpdateBatteryAttribute(self, Devices, MsgSrcAddr, MsgSrcEp): model_name = self.ListOfDevices[MsgSrcAddr].get("Model", None) @@ -33,59 +42,48 @@ def UpdateBatteryAttribute(self, Devices, MsgSrcAddr, MsgSrcEp): # Compute Battery % mainVolt = battVolt = battRemainingVolt = battRemainPer = None - if "0000" in self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]: - mainVolt = float(self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0000"]) - if "0010" in self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]: - battVolt = float(self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0010"]) - if "0020" in self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"] and self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0020"] != {}: - battRemainingVolt = float(self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0020"]) - if "0021" in self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"] and self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0021"] != {}: - battRemainPer = float(self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"]["0021"]) - self.log.logging( - "Cluster", - "Debug", - f'readCluster 0001 - Device: {MsgSrcAddr} Model: {self.ListOfDevices[MsgSrcAddr]["Model"]} mainVolt:{mainVolt} , battVolt:{battVolt}, battRemainingVolt: {battRemainingVolt}, battRemainPer:{battRemainPer} ', - MsgSrcAddr, - ) + + device_power_cluster = self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp]["0001"] + + mainVolt = get_float_value(device_power_cluster, ["0000"]) + battVolt = get_float_value(device_power_cluster, ["0010"]) + battRemainingVolt = get_float_value(device_power_cluster, ["0020"]) + battRemainPer = get_float_value(device_power_cluster, ["0021"]) + + battery_percengtage_timestamp = self.ListOfDevices[MsgSrcAddr].get("BatteryPercentage_TimeStamp", 0) + battery_voltage_timestamp = self.ListOfDevices[MsgSrcAddr].get("BatteryVoltage_TimeStamp", 0) value = None # Based on % ( 0x0021 ) - if battRemainPer: + if battRemainPer and battery_percengtage_timestamp >= battery_voltage_timestamp: value = battRemainPer - BatteryPercentageConverter = get_deviceconf_parameter_value(self, self.ListOfDevices[MsgSrcAddr]["Model"], "BatteryPercentageConverter") + BatteryPercentageConverter = get_deviceconf_parameter_value(self, model_name, "BatteryPercentageConverter") if BatteryPercentageConverter: value = round(value / BatteryPercentageConverter) # Based on Remaining Voltage - elif battRemainingVolt: - MaxBatteryVoltage = get_deviceconf_parameter_value(self, self.ListOfDevices[MsgSrcAddr]["Model"], "MaxBatteryVoltage", 30) - MinBatteryVoltage = get_deviceconf_parameter_value(self, self.ListOfDevices[MsgSrcAddr]["Model"], "MinBatteryVoltage", 25) + elif battRemainingVolt and battery_voltage_timestamp >= battery_percengtage_timestamp: + MaxBatteryVoltage = get_deviceconf_parameter_value(self, model_name, "MaxBatteryVoltage", 30) + MinBatteryVoltage = get_deviceconf_parameter_value(self, model_name, "MinBatteryVoltage", 25) value = voltage2batteryP(battRemainingVolt, MaxBatteryVoltage, MinBatteryVoltage) + self.log.logging( ["Cluster", "BatteryManagement"], "Debug", f'UpdateBatteryAttribute - Device: {MsgSrcAddr} Model: {model_name} mainVolt:{mainVolt} , battVolt:{battVolt}, battRemainingVolt: {battRemainingVolt}, battRemainPer:{battRemainPer} => value: {value} ', MsgSrcAddr, ) + if value is None: return - self.log.logging( - "Cluster", - "Debug", - f'readCluster 0001 - Device: {MsgSrcAddr} Model: {self.ListOfDevices[MsgSrcAddr]["Model"]} Updating battery {self.ListOfDevices[MsgSrcAddr]["Battery"]} to {value}', - MsgSrcAddr, - ) - - self.ListOfDevices[MsgSrcAddr]["BatteryUpdateTime"] = int(time()) + self.ListOfDevices[MsgSrcAddr]["BatteryUpdateTime"] = int(time.time()) if value != self.ListOfDevices[MsgSrcAddr]["Battery"]: self.ListOfDevices[MsgSrcAddr]["Battery"] = value Update_Battery_Device(self, Devices, MsgSrcAddr, value) - self.log.logging("Cluster", "Debug", f'readCluster 0001 - Device: {MsgSrcAddr} Model: {self.ListOfDevices[MsgSrcAddr]["Model"]} Updating battery to {value}', MsgSrcAddr) - if "IASBattery" in self.ListOfDevices[MsgSrcAddr]: - # Remove it as we rely on the Power Cluster instead - del self.ListOfDevices[MsgSrcAddr]["IASBattery"] + self.ListOfDevices[MsgSrcAddr].pop("IASBattery", None) def hack_battery_to_main_power(self, Nwkid): + power_source = self.ListOfDevices[Nwkid].get("PowerSource") + mac_capa = self.ListOfDevices[Nwkid].get("MacCapa") - if self.ListOfDevices[Nwkid]["PowerSource"] == "Main" or self.ListOfDevices[Nwkid]["MacCapa"] in ( "84", "8e", ): + if power_source == "Main" or mac_capa in {"84", "8e"}: # This is a Main Powered device. Make sure we do not report battery - self.ListOfDevices[Nwkid]["Battery"] = {} - return + self.ListOfDevices[Nwkid]["Battery"] = {} \ No newline at end of file diff --git a/Modules/command.py b/Modules/command.py index ba5b45dac..172e17a53 100644 --- a/Modules/command.py +++ b/Modules/command.py @@ -49,13 +49,13 @@ tuya_dimmer_dimmer, tuya_dimmer_onoff, tuya_energy_onoff, tuya_garage_door_action, tuya_switch_command, tuya_watertimer_command, - tuya_window_cover_calibration) + tuya_window_cover_calibration, tuya_polling_control) from Modules.tuyaSiren import (tuya_siren2_trigger, tuya_siren_alarm, tuya_siren_humi_alarm, tuya_siren_temp_alarm) from Modules.tuyaTRV import (tuya_coil_fan_thermostat, tuya_fan_speed, tuya_lidl_set_mode, tuya_trv_brt100_set_mode, tuya_trv_mode, tuya_trv_onoff) -from Modules.tuyaTS0601 import ts0601_actuator, ts0601_extract_data_point_infos +from Modules.tuyaTS0601 import ts0601_actuator, ts0601_extract_data_point_infos, ts0601_curtain_calibration_cmd from Modules.zigateConsts import (THERMOSTAT_LEVEL_2_MODE, THERMOSTAT_LEVEL_3_MODE) @@ -119,6 +119,7 @@ "ThermoMode_5", "ThermoMode_6", "ThermoMode_7", + "ThermoMode_8", "ThermoModeEHZBRTS", "AirPurifierMode", "FanSpeed", @@ -140,7 +141,10 @@ "ThermoOnOff", "ShutterCalibration", "SwitchAlarm", - "TamperSwitch" + "SwitchCalibration", + "TamperSwitch", + "PollingControl", + "PollingControlV2" ] @@ -222,6 +226,10 @@ def handle_command_stop(self,Devices, DeviceID, Unit, Nwkid, EPout, DeviceType, actuator_stop( self, Nwkid, EPout, "WindowCovering") if DeviceType in ( "CurtainInverted", "Curtain"): + if ts0601_extract_data_point_infos( self, model_name): + ts0601_actuator(self, Nwkid, "CurtainState", 1) + update_domoticz_widget(self, Devices, DeviceID, Unit, 17, "0", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + # Refresh will be done via the Report Attribute return @@ -268,6 +276,13 @@ def handle_command_off(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, Device update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) return + if DeviceType == "SwitchCalibration" and model_name == "TS0601-Moes-Curtain": + # Switch Off alibration + self.log.logging("Command", "Status", "mgtCommand : Switch Off Calibration on %s/%s" % (Nwkid,EPout)) + update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + ts0601_curtain_calibration_cmd( self, Nwkid, EPout, 0x07, mode=0) + return + if DeviceType == "SwitchAlarm" and model_name == "TS0601-_TZE200_t1blo2bj": tuya_siren2_trigger(self, Nwkid, '00') update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) @@ -325,7 +340,7 @@ def handle_command_off(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, Device request_read_device_status(self, Nwkid) return - if DeviceType == ("ThermoMode_2", ): + if DeviceType in ("ThermoMode_2", ): self.log.logging("Command", "Debug", f"handle_command_off : Set Level for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid) if ts0601_extract_data_point_infos( self, model_name): @@ -335,6 +350,12 @@ def handle_command_off(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, Device tuya_trv_mode(self, Nwkid, 0) update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) return + + if DeviceType in ("PollingControl", "PollingControlV2", ): + self.log.logging("Command", "Log", f"handle_command_off : PollingControl Set Level/Off for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid) + tuya_polling_control(self, Nwkid, DeviceType, Level) + update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + return if DeviceType in ("ThermoMode_4", "ThermoMode_5", "ThermoMode_6", "ThermoMode_7"): self.log.logging("Command", "Debug", f"handle_command_off : Set Level for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid) @@ -398,16 +419,21 @@ def handle_command_off(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, Device else: actuator_on(self, Nwkid, EPout, "WindowCovering") - if DeviceType in ( "CurtainInverted", "Curtain"): + if DeviceType in ( "CurtainInverted", ): # Refresh will be done via the Report Attribute return elif DeviceType in ( "Venetian", "Vanne", "Curtain"): + if model_name in ( "PR412", "CPR412", "CPR412-E"): actuator_off(self, Nwkid, EPout, "Light") - elif ( DeviceType in ("Vanne", "Curtain",) or model_name in ( "TS130F",) ): + elif DeviceType in ( "Curtain", ) and ts0601_extract_data_point_infos( self, model_name): + ts0601_actuator(self, Nwkid, "CurtainState", 2) + update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + return + elif ( DeviceType in ("Vanne", "Curtain",) or model_name in ( "TS130F",) ): actuator_off(self, Nwkid, EPout, "WindowCovering") elif DeviceType in ( "CurtainInverted", "Curtain"): @@ -491,11 +517,17 @@ def handle_command_on(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, DeviceT if model_name in ( "TS0601-switch", "TS0601-2Gangs-switch", "TS0601-2Gangs-switch", ): self.log.logging("Command", "Debug", "mgtCommand : On for Tuya Switches Gang/EPout: %s" % EPout) - tuya_switch_command(self, Nwkid, "01", gang=int(EPout, 16)) update_domoticz_widget(self, Devices, DeviceID, Unit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) return + if DeviceType == "SwitchCalibration" and model_name == "TS0601-Moes-Curtain": + # Switch On calibration + self.log.logging("Command", "Status", "mgtCommand : Switch ON Calibration on %s/%s" % (Nwkid,EPout)) + update_domoticz_widget(self, Devices, DeviceID, Unit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + ts0601_curtain_calibration_cmd( self, Nwkid, EPout, 0x07, mode=1) + return + if DeviceType == "SwitchAlarm" and model_name == "TS0601-_TZE200_t1blo2bj": tuya_siren2_trigger(self, Nwkid, '01') update_domoticz_widget(self, Devices, DeviceID, Unit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) @@ -580,7 +612,7 @@ def handle_command_on(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, DeviceT else: actuator_off(self, Nwkid, EPout, "WindowCovering") - if DeviceType in ( "CurtainInverted", "Curtain"): + if DeviceType in ( "CurtainInverted", ): # Refresh will be done via the Report Attribute return @@ -588,15 +620,19 @@ def handle_command_on(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, DeviceT if model_name in ("PR412", "CPR412", "CPR412-E"): actuator_on(self, Nwkid, EPout, "Light") + elif DeviceType in ( "Curtain", ) and ts0601_extract_data_point_infos( self, model_name): + ts0601_actuator(self, Nwkid, "CurtainState", 0) + update_domoticz_widget(self, Devices, DeviceID, Unit, 0, "Open", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + return + elif DeviceType in ( "Vanne", "Curtain",) or model_name in ( "TS130F",): actuator_on(self, Nwkid, EPout, "WindowCovering") elif DeviceType in ( "CurtainInverted", "Curtain"): return - + else: actuator_off(self, Nwkid, EPout, "WindowCovering") - # Refresh will be done via the Report Attribute return @@ -658,7 +694,7 @@ def handle_command_setlevel(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, D self.log.logging( "Command", "Debug", f"handle_command_setlevel : Set Level for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid, ) if DeviceType == "ThermoSetpoint": - _set_level_setpoint(self, Devices, DeviceID, Unit, Nwkid, EPout, Level, BatteryLevel, SignalLevel,DeviceType, forceUpdateDev ) + _set_level_setpoint(self, Devices, DeviceID, Unit, Nwkid, EPout, model_name, Level, BatteryLevel, SignalLevel,DeviceType, forceUpdateDev ) return if DeviceType == "TempSetCurrent": @@ -839,6 +875,12 @@ def handle_command_setlevel(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, D update_domoticz_widget(self, Devices, DeviceID, Unit, int(Level // 10), Level, BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev ) return + if DeviceType in ("PollingControl", "PollingControlV2", ): + self.log.logging("Command", "Log", f"handle_command_setlevel : PollingControl Set Level for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid) + tuya_polling_control(self, Nwkid, DeviceType, Level) + update_domoticz_widget(self, Devices, DeviceID, Unit, int(Level // 10), Level, BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev ) + return + if DeviceType == "ThermoMode_4": self.log.logging( "Command", @@ -859,14 +901,13 @@ def handle_command_setlevel(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, D ts0601_actuator(self, Nwkid, "TRV6SystemMode", int(Level // 10)) return + if DeviceType == "ThermoMode_8" and ts0601_extract_data_point_infos( self, model_name): + ts0601_actuator(self, Nwkid, "TRV8SystemMode", int(Level // 10)) + return + if DeviceType in ("ThermoMode_5", "ThermoMode_6"): - self.log.logging( - "Command", - "Debug", - "handle_command_setlevel : Set Level for Device: %s EPout: %s Unit: %s DeviceType: %s Level: %s" - % (Nwkid, EPout, Unit, DeviceType, Level), - Nwkid, - ) + self.log.logging( "Command", "Debug", "handle_command_setlevel : Set Level for Device: %s EPout: %s Unit: %s DeviceType: %s Level: %s" % ( + Nwkid, EPout, Unit, DeviceType, Level), Nwkid, ) if model_name == "TS0601-_TZE200_chyvmhay": # 1: // manual 2: // away 0: // auto @@ -920,26 +961,22 @@ def handle_command_setlevel(self,Devices, DeviceID, Unit, Level, Nwkid, EPout, D # Transform slider % into analog value lift = min(max((255 * Level) // 100, 1), 255) - self.log.logging( - "Command", - "Debug", - f"handle_command_setlevel : profalux_MoveToLiftAndTilt: {Nwkid} BSO-Volet Lift: Level: {Level} Lift: {lift}", - Nwkid, - ) + self.log.logging( "Command", "Debug", f"handle_command_setlevel : profalux_MoveToLiftAndTilt: {Nwkid} BSO-Volet Lift: Level: {Level} Lift: {lift}", Nwkid, ) profalux_MoveToLiftAndTilt(self, Nwkid, level=lift) elif DeviceType == "BSO-Orientation": if profalux: Tilt = Level - 10 - self.log.logging( - "Command", - "Debug", - f"handle_command_setlevel : profalux_MoveToLiftAndTilt: {Nwkid} BSO-Orientation : Level: {Level} Tilt: {Tilt}", - Nwkid, - ) + self.log.logging( "Command", "Debug", f"handle_command_setlevel : profalux_MoveToLiftAndTilt: {Nwkid} BSO-Orientation : Level: {Level} Tilt: {Tilt}", Nwkid, ) profalux_MoveToLiftAndTilt(self, Nwkid, tilt=Tilt) elif DeviceType in ( "WindowCovering", "Venetian", "Vanne", "Curtain", "VenetianInverted", "VanneInverted", "CurtainInverted"): + if ts0601_extract_data_point_infos( self, model_name): + self.log.logging( "Command", "Debug", f"handle_command_setlevel : Tuya TS0601: {Nwkid} Level: {Level}", Nwkid, ) + ts0601_actuator(self, Nwkid, "CurtainLevel", Level) + update_domoticz_widget(self, Devices, DeviceID, Unit, 2, str(Level), BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) + return + _set_level_windows_covering(self, DeviceType, Nwkid, EPout, Level) elif DeviceType == "AlarmWD": @@ -1072,7 +1109,7 @@ def _set_level_set_current_temp(self, Devices, DeviceID, Unit, Nwkid, EPout, Lev return -def _set_level_setpoint(self, Devices, DeviceID, Unit, Nwkid, EPout, Level, BatteryLevel, SignalLevel, DeviceType, forceUpdateDev): +def _set_level_setpoint(self, Devices, DeviceID, Unit, Nwkid, EPout, model_name, Level, BatteryLevel, SignalLevel, DeviceType, forceUpdateDev): # Log the command self.log.logging( "Command", "Debug", f"_set_level_setpoint : Set Level for Device: {Nwkid} EPout: {EPout} Unit: {Unit} DeviceType: {DeviceType} Level: {Level}", Nwkid, ) @@ -1089,7 +1126,8 @@ def _set_level_setpoint(self, Devices, DeviceID, Unit, Nwkid, EPout, Level, Batt update_domoticz_widget( self, Devices, DeviceID, Unit, 0, str(normalized_level), BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev ) # Request a refresh of the attribute in the next Heartbeat - request_read_device_status(self, Nwkid) + if get_deviceconf_parameter_value(self, model_name, "READ_ATTRIBUTE_AFTER_COMMAND", return_default=True): + request_read_device_status(self, Nwkid) return diff --git a/Modules/deviceAnnoucement.py b/Modules/deviceAnnoucement.py index 78c4279b1..7e836231f 100755 --- a/Modules/deviceAnnoucement.py +++ b/Modules/deviceAnnoucement.py @@ -241,7 +241,7 @@ def device_annoucementv2(self, Devices, MsgData, MsgLQI): tuya_sirene_registration(self, NwkId) elif self.ListOfDevices[NwkId]["Model"] in (TUYA_eTRV_MODEL): - tuya_eTRV_registration(self, NwkId, False) + tuya_eTRV_registration(self, NwkId, tuya_data_request=False) handle_device_specific_needs(self, Devices, NwkId) diff --git a/Modules/domoCreate.py b/Modules/domoCreate.py index 9482011eb..fba21de01 100644 --- a/Modules/domoCreate.py +++ b/Modules/domoCreate.py @@ -471,8 +471,8 @@ def colorcontrol_if_undefinded( self, Nwkid ): def create_native_widget( self, Devices, NwkId, DeviceID_IEEE, Ep, widget_name): - self.log.logging( "WidgetCreation", "Debug", "create_native_widget - NwkId: %s Ieee: %s Widget %s Dz2023.1: %s" %( - NwkId, DeviceID_IEEE, widget_name, is_domoticz_new_blind(self)), NwkId) + self.log.logging( "WidgetCreation", "Debug", "create_native_widget - %s NwkId: %s Ieee: %s Widget %s Dz2023.1: %s" %( + widget_name, NwkId, DeviceID_IEEE, widget_name, is_domoticz_new_blind(self)), NwkId) if widget_name in SIMPLE_WIDGET: widget_record = SIMPLE_WIDGET[ widget_name ] @@ -709,6 +709,11 @@ def set_default_value( self, Devices, device_id_ieee, device_unit, widget_record "Subtype": 1, "Switchtype": 0 }, + "Lux20MinAverage": { + "Type": 246, + "Subtype": 1, + "Switchtype": 0 + }, "LvlControl": { "Type": 244, "Subtype": 73, @@ -731,6 +736,12 @@ def set_default_value( self, Devices, device_id_ieee, device_unit, widget_record "Type": 243, "Subtype": 19 }, + "BatteryPercentage": { + "Type": 243, + "Subtype": 6, + "Switchtype": 0 + }, + "P1Meter": { "Type": 250, "Subtype": 1, @@ -795,11 +806,12 @@ def set_default_value( self, Devices, device_id_ieee, device_unit, widget_record "Options": "1;ppm" }, - "phMeter": { "widgetType": "Custom", "Options": "1;ph" }, + "phMeter": { "widgetType": "Custom", "Options": "1;pH" }, "ec": { "widgetType": "Custom", "Options": "1;µS/cm" }, "orp": { "widgetType": "Custom", "Options": "1;mV" }, "freeChlorine": { "widgetType": "Custom", "Options": "1;mg/L" }, "salinity": { "widgetType": "Custom", "Options": "1;ppm" }, + "tds": { "widgetType": "Custom", "Options": "1;ppm" }, "Strength": { "Type": 243, @@ -821,6 +833,16 @@ def set_default_value( self, Devices, device_id_ieee, device_unit, widget_record "Subtype": 73, "Switchtype": 0 }, + "SwitchCalibration": { + "Type": 244, + "Subtype": 73, + "Switchtype": 0 + }, + "SwitchCleaning": { + "Type": 244, + "Subtype": 73, + "Switchtype": 0 + }, "Tamper": { "Type": 243, "Subtype": 22, @@ -877,6 +899,7 @@ def set_default_value( self, Devices, device_id_ieee, device_unit, widget_record "Switchtype": 0, "Image": 11 }, + "RainIntensity": { "widgetType": "Custom", "Options": "1;mV" }, "WaterCounter": { "Type": 243, "Subtype": 28, diff --git a/Modules/domoMaj.py b/Modules/domoMaj.py index 153abed30..db499ae2d 100644 --- a/Modules/domoMaj.py +++ b/Modules/domoMaj.py @@ -88,8 +88,7 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, # Attribute_ : If used This is the Attribute from readCluster. Will help to route to the right action # Color_ : If used This is the color value to be set - self.log.logging( "Widget", "Debug", "_domo_maj_one_cluster_type_entry WidgetEp: %s, Widget_Idx: %s, WidgetType: %s Value: %s Color: %s" % ( - WidgetEp, Widget_Idx, WidgetType, value, Color_), NwkId, ) + self.log.logging( "Widget", "Debug", f"_domo_maj_one_cluster_type_entry NwkId: {NwkId}, Ep: {Ep}, device_id_ieee: {device_id_ieee}, model_name: {model_name}, ClusterType: {ClusterType}, ClusterTypeList: {ClusterTypeList}, ClusterId: {ClusterId}, value: {value}, Attribute_: {Attribute_}, Color_: {Color_}, WidgetEp: {WidgetEp}, Widget_Idx: {Widget_Idx}, WidgetType: {WidgetType}", NwkId, ) if WidgetEp == "00": # Old fashion / keep it for backward compatibility @@ -107,9 +106,8 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, prev_nValue, prev_sValue = domo_read_nValue_sValue(self, Devices, device_id_ieee, device_unit) switchType, Subtype, _ = domo_read_SwitchType_SubType_Type(self, Devices, device_id_ieee, device_unit) - self.log.logging( "Widget", "Debug", "------> ClusterType: %s WidgetEp: %s Widget_Idx: %s WidgetType: %s Attribute_: %s" % ( - ClusterType, WidgetEp, Widget_Idx, WidgetType, Attribute_), NwkId, ) - + self.log.logging( "Widget", "Debug", f"------> device_unit: {device_unit}, prev_nValue: {prev_nValue}, prev_sValue: {prev_sValue} switchType: {switchType}, Subtype: {Subtype}", NwkId,) + SignalLevel, BatteryLevel = RetreiveSignalLvlBattery(self, NwkId) self.log.logging("Widget", "Debug", "------> SignalLevel: %s , BatteryLevel: %s" % (SignalLevel, BatteryLevel), NwkId) @@ -137,6 +135,10 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, nValue = int(value) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, text, BatteryLevel, SignalLevel) + if WidgetType == "BatteryPercentage" and ClusterType == "Voltage" and Attribute_ == "0021": + sValue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, sValue, BatteryLevel, SignalLevel) + if ClusterType == "Alarm" and WidgetType == "Alarm_ZL3" and Attribute_ == "0020": if value is None or len(value) == 0: return @@ -377,10 +379,10 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, check_set_meter_widget( self, Devices, NwkId, device_id_ieee, device_unit, prev_nValue, prev_sValue, 0) instant, _summation = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, prev_nValue, prev_sValue, "0;0") summation = round(float(zlinky_sum_all_indexes( self, NwkId )), 2) - self.log.logging(["ZLinky","Electric"], "Debug", "------> Summation for Meter : %s" %summation) + self.log.logging(["ZLinky","Electric"], "Debug", "------> Summation for Meter : %s" %summation, NwkId) sValue = "%s;%s" % (instant, summation) - self.log.logging(["ZLinky","Electric"], "Debug", "------> : " + sValue) + self.log.logging(["ZLinky","Electric"], "Debug", "------> : " + sValue, NwkId) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "Meter" and Attribute_ == "050f": @@ -389,7 +391,7 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, _instant, summation = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, prev_nValue, prev_sValue, "0;0") instant = round(float(value), 2) sValue = "%s;%s" % (instant, summation) - self.log.logging(["Widget","Electric"], "Debug", f"- {device_id_ieee} {device_unit} Instant Power received {value} converted to {instant} and {summation} resulting in {sValue}") + self.log.logging(["Widget","Electric"], "Debug", f"- {device_id_ieee} {device_unit} Instant Power received {value} converted to {instant} and {summation} resulting in {sValue}", NwkId) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, sValue, BatteryLevel, SignalLevel) @@ -413,7 +415,7 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, # No summation retreive, so we make sure that EnergyMeterMode is # correctly set to 1 (compute), if not adjust - self.log.logging(["Widget","Electric"], "Debug", f"------> Update Meter/Meter : {device_id_ieee} {device_unit} {sValue}") + self.log.logging(["Widget","Electric"], "Debug", f"------> Update Meter/Meter : {device_id_ieee} {device_unit} {sValue}", NwkId) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, sValue, BatteryLevel, SignalLevel) if "WaterCounter" in ClusterType and WidgetType == "WaterCounter": @@ -532,9 +534,10 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, update_domoticz_widget(self, Devices, device_id_ieee, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) if "Valve" in ClusterType and (WidgetType == "Valve" and Attribute_ in ("026d", "4001", "0008")): - nValue = round(value, 1) - sValue = str(nValue) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "Valve (Pi Demand) %s WidgetType: %s Value: %s (%s) Attribute_: %s" % ( + NwkId, WidgetType, value, type(value), Attribute_), NwkId) + sValue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, sValue, BatteryLevel, SignalLevel) if "ThermoMode" in ClusterType: # Thermostat Mode self.log.logging("Widget", "Debug", "ThermoMode %s WidgetType: %s Value: %s (%s) Attribute_: %s" % ( @@ -722,39 +725,47 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 5, "50", BatteryLevel, SignalLevel) if ClusterType == "PM25" and WidgetType == "PM25": - nvalue = round(value, 0) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "PM25" and WidgetType == "SmokePPM": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "phMeter" and WidgetType == "phMeter": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> pH: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "ec" and WidgetType == "ec": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> EC: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "orp" and WidgetType == "orp": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> ORP: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "freeChlorine" and WidgetType == "freeChlorine": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> FreeChlorine: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "salinity" and WidgetType == "salinity": - nvalue = int(value) - svalue = "%s" % (nvalue,) - update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Salinity: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) + + if ClusterType == "tds" and WidgetType == "tds": + self.log.logging("Widget", "Debug", "------> TDS: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) + + if ClusterType == "RainIntensity" and WidgetType == "RainIntensity": + self.log.logging("Widget", "Debug", "------> RainIntensity: %s" % (value,), NwkId) + svalue = str(value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "Alarm" and WidgetType == "AirPurifierAlarm": @@ -935,6 +946,7 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, or ("ThermoMode" in ClusterType and WidgetType == "ACMode_2") or ("ThermoMode" in ClusterType and WidgetType == "ACSwing" and Attribute_ == "fd00") or ("ThermoMode" in ClusterType and WidgetType == "ThermoMode_7" and Attribute_ == "001c") + or ("ThermoMode" in ClusterType and WidgetType == "ThermoMode_8" and Attribute_ == "001c") or (WidgetType == "KF204Switch" and ClusterType in ("Switch", "Door")) or (WidgetType == "Valve" and Attribute_ == "0014") or ("ThermoMode" in ClusterType and WidgetType == "ThermoOnOff") @@ -948,20 +960,26 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, self.log.logging( "Widget", "Debug", "------> Generic Widget for %s ClusterType: %s WidgetType: %s Value: %s" % ( NwkId, ClusterType, WidgetType, value), NwkId, ) - if ClusterType == "Switch" and WidgetType == "LvlControl": - # Called with ClusterId: 0x0006 but we have to update a Dimmer, so we need to keep the level - nValue = int(value) + if WidgetType == "Tamper" and ClusterType != "Alarm": + self.log.logging( "Widget", "Debug", "------> Generic Widget - %s rejecting WidgetType: %s and ClusterType: %s" %( + NwkId, ClusterType, WidgetType), NwkId) + return + + elif WidgetType == "LvlControl" and ClusterType == "Switch": + self.log.logging("Widget", "Debug", f"------> ClusterId: 0x0006 but we have to update a Dimmer value: {value}", NwkId) + + nValue = int(value, 16) sValue = prev_sValue - if switchType in (13, 16): - # Correct for Blinds where we have to display % + + if is_dimmable_blind(self, Devices, device_id_ieee, device_unit): + # Handle dimmable blinds with percentage display if value == "00": - nValue = 0 - sValue = "0" + nValue, sValue = 0, "0" elif value == "01" and prev_sValue == "100": - nValue = 1 - sValue = "100" + nValue, sValue = 1, "100" else: nValue = 2 + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif ClusterType == "Switch" and WidgetType == "Alarm": @@ -1114,8 +1132,8 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType in ("VenetianInverted", "Venetian", "WindowCovering", "VanneInverted", "Vanne", "Curtain", "CurtainInverted"): - _value = int(value, 16) - self.log.logging( "Widget", "Debug", "------> %s/%s ClusterType: %s Updating %s Value: %s" % (NwkId, Ep, ClusterType, WidgetType, _value), NwkId, ) + _value = int(value, 16) if isinstance(value, str) else value + self.log.logging( "Widget", "Debug", "------> Generic Widget for %s/%s ClusterType: %s Updating %s Value: %s" % (NwkId, Ep, ClusterType, WidgetType, _value), NwkId, ) if WidgetType in ("VenetianInverted", "VanneInverted"): _value = 100 - _value self.log.logging("Widget", "Debug", "------> Patching %s/%s Value: %s" % (NwkId, Ep, _value), NwkId) @@ -1163,15 +1181,19 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, if "WindowCovering" in ClusterType and WidgetType in ("VenetianInverted", "Venetian", "Vanne", "VanneInverted", "WindowCovering", "Curtain", "CurtainInverted", "Blind"): + self.log.logging(["Widget", "Electric"], "Debug", "------> WindowCovering : %s" % value, NwkId) nValue, sValue = _domo_convert_windows_covering( self, value, Devices, device_id_ieee, device_unit, NwkId, WidgetType ) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "LvlControl" in ClusterType: # LvlControl ( 0x0008) + self.log.logging("Widget", "Debug", "------> LvlControl : %s" % value, NwkId) tuple_value = _domo_convert_level_control( self, Devices, device_id_ieee, device_unit, value, NwkId, switchType, WidgetType, prev_nValue, prev_sValue) if tuple_value : update_domoticz_widget(self, Devices, device_id_ieee, device_unit, tuple_value[0], tuple_value[1], BatteryLevel, SignalLevel, ForceUpdate_=tuple_value[2]) if ClusterType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ) and ClusterType == WidgetType: + self.log.logging(["Widget", "Electric"], "Debug", "------> ColorControl %s : %s" % (ClusterType, value), NwkId) + # We just manage the update of the Dimmer (Control Level) nValue, sValue = _domo_convert_colorcontrol( self, value ) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, str(sValue), BatteryLevel, SignalLevel, Color_) @@ -1196,6 +1218,10 @@ def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, nValue, sValue = _domo_convert_lux( value) update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) + if "Lux" in ClusterType and WidgetType == "Lux20MinAverage" and Attribute_ == "ff00": + nValue, sValue = _domo_convert_lux( value) + update_domoticz_widget(self, Devices, device_id_ieee, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) + # Check if this Device belongs to a Group. In that case update group CheckUpdateGroup(self, NwkId, Ep, ClusterId) @@ -1216,7 +1242,7 @@ def _domo_convert_windows_covering( self, value, Devices, DeviceId, Unit, NwkId, elif value == 100: nValue = 1 else: - nValue = dimm_blind_nvalue if dimm_blind_nvalue else 2 + nValue = dimm_blind_nvalue or 2 self.log.logging("Widget", "Debug", "------> %s %s Value: %s:%s" % (WidgetType, NwkId, nValue, value), NwkId) return nValue, str(value) @@ -1243,14 +1269,14 @@ def _domo_convert_lux( value): def _domo_convert_level_control( self, Devices, DeviceId, Unit, value, NwkId, switchType, WidgetType, prev_nValue, prev_sValue): - if WidgetType == "LvlControl" or ( WidgetType in ( "BSO-Volet", "Blind", ) ): + if WidgetType == "LvlControl" or ( WidgetType in ( "BSO-Volet", "Blind", "Curtain") ): # We need to handle the case, where we get an update from a Read Attribute or a Reporting message # We might get a Level, but the device is still Off and we shouldn't make it On . self.log.logging("Widget", "Debug", "_domo_convert_level_control input value: -> %s" % value, NwkId) normalized_value = normalized_lvl_value( switchType, value ) - self.log.logging( "Widget", "Debug", "_domo_convert_level_control normalized Value: -> %s previous nValue/sValue %s:%s" % ( - normalized_value, prev_nValue, prev_sValue), NwkId, ) + self.log.logging( "Widget", "Debug", "_domo_convert_level_control normalized switchType: %s Value: -> %s previous nValue/sValue %s:%s" % ( + switchType, normalized_value, prev_nValue, prev_sValue), NwkId, ) dimm_blind_nvalue = is_dimmable_blind(self, Devices, DeviceId, Unit) self.log.logging( "Widget", "Debug", "_domo_convert_level_control dimm_blind_value %s" % (dimm_blind_nvalue), NwkId, ) @@ -1568,7 +1594,7 @@ def check_set_meter_widget( self, Devices, NwkId, DeviceId, Unit, oldnValue, old Options = {'EnergyMeterMode': '0'} _device_options = domo_read_Options( self, Devices, DeviceId, Unit,) - self.log.logging( "Widget", "Debug", "check_set_meter_widget Options: %s" %_device_options) + self.log.logging( "Widget", "Debug", "check_set_meter_widget Options: %s" %_device_options, NwkId) # Do we have the Energy Mode calculation already set ? if "EnergyMeterMode" in _device_options: @@ -1633,13 +1659,11 @@ def normalized_lvl_value( switchType, value ): # Normalize analog value to percentage (0-100) normalized_value = round((analog_value / 255) * 100) - # Looks like in the case of the Profalux shutter, we never get 0 or 100 - if switchType in (13, 14, 15, 16): - if normalized_value == 1 and analog_value == 1: - normalized_value = 0 - if normalized_value == 99 and analog_value == 254: - normalized_value = 100 + if switchType in (3, 13, 14, 15, 16, 21): + # In case of Blind/Venetian widgets return the value for 0 to 100% + return normalized_value + # In other case ( Dim, Light never return 0) return max(normalized_value, 1) # Ensure normalized value is at least 1 @@ -1709,4 +1733,4 @@ def _retreive_summation_power(self, NwkId, Ep): if value_0000 not in ({}, "", "0"): return int(float(value_0000)) - return None \ No newline at end of file + return None diff --git a/Modules/domoTools.py b/Modules/domoTools.py index d2449767d..995e0eed5 100644 --- a/Modules/domoTools.py +++ b/Modules/domoTools.py @@ -313,10 +313,11 @@ def timedOutDevice(self, Devices, NwkId=None, MarkTimedOut=True): self.log.logging("WidgetLevel3", "Debug", f"timedOutDevice Object {NwkId} MarkTimedOut: {MarkTimedOut}") _IEEE = device_info["IEEE"] - - if MarkTimedOut and not domo_read_TimedOut(self, Devices, _IEEE): + timed_out = domo_read_TimedOut(self, Devices, _IEEE) + + if MarkTimedOut and not timed_out: timeout_widget_api(self, Devices, _IEEE, 1) - else: + elif not MarkTimedOut and timed_out: timeout_widget_api(self, Devices, _IEEE, 0) @@ -495,8 +496,10 @@ def GetType(self, Addr, Ep): "phMeter": "phMeter", "ec": "ec", "orp": "orp", + "RainIntensity": "RainIntensity", "freeChlorine": "freeChlorine", "salinity": "salinity", + "tds": "tds" } def TypeFromCluster(self, cluster, create_=False, ProfileID_="", ZDeviceID_="", ModelName=""): diff --git a/Modules/domoticzAbstractLayer.py b/Modules/domoticzAbstractLayer.py index 172f29993..f1f4f2ed2 100644 --- a/Modules/domoticzAbstractLayer.py +++ b/Modules/domoticzAbstractLayer.py @@ -396,12 +396,18 @@ def domo_update_api(self, Devices, DeviceID_, Unit_, nValue, sValue, SignalLevel TimedOut (int, optional): Timeoud flag 0 to unset the Timeout. Defaults to None. Color (str, optional): Color . Defaults to "". """ + nwkid = None + try: + nwkid = self.IEEE2NWK[DeviceID_] + except KeyError : + pass + self.log.logging("AbstractDz", "Debug", "domo_update_api: DeviceID_ : %s Unit_: %s nValue: %s sValue: %s SignalLevel: %s BatteryLevel: %s TimedOut: %s Color: %s : %s" %( - DeviceID_, Unit_, nValue, sValue, SignalLevel, BatteryLevel, TimedOut, Color, Options), DeviceID_) + DeviceID_, Unit_, nValue, sValue, SignalLevel, BatteryLevel, TimedOut, Color, Options), nwkid) if nValue is None: self.log.logging("AbstractDz", "Error", "domo_update_api: DeviceID_ : %s Unit_: %s nValue: %s sValue: %s SignalLevel: %s BatteryLevel: %s TimedOut: %s Color: %s : %s" %( - DeviceID_, Unit_, nValue, sValue, SignalLevel, BatteryLevel, TimedOut, Color, Options), DeviceID_) + DeviceID_, Unit_, nValue, sValue, SignalLevel, BatteryLevel, TimedOut, Color, Options), nwkid) return if DOMOTICZ_EXTENDED_API: @@ -428,7 +434,7 @@ def domo_update_api(self, Devices, DeviceID_, Unit_, nValue, sValue, SignalLevel Devices[DeviceID_].Units[Unit_].Options = Options except Exception as e: - self.log.logging("AbstractDz", "Debug", f"domo_update_api: Cannot Write Attribute Option with {Options}") + self.log.logging("AbstractDz", "Debug", f"domo_update_api: Cannot Write Attribute Option with {Options}", nwkid) Devices[DeviceID_].Units[Unit_].Update(Log=(not SuppressTriggers) ) return @@ -542,10 +548,12 @@ def domo_read_TimedOut( self, Devices, DeviceId_ ): if DOMOTICZ_EXTENDED_API and DeviceId_ in Devices: return Devices[ DeviceId_].TimedOut - # Legacy + # Legacy, return the TimedOut flag of 1st unit return next( ( 1 for x in Devices if Devices[x].DeviceID == DeviceId_ and Devices[x].TimedOut ), 0, ) - +def domo_read_legacy_TimedOut( self, Devices, DeviceId_, UnitId_ ): + return Devices[ UnitId_ ].TimedOut + def domo_read_LastUpdate(self, Devices, DeviceId_, Unit_): self.log.logging("AbstractDz", "Debug", f"domo_read_LastUpdate: DeviceID: {DeviceId_} Unit {Unit_}") @@ -699,31 +707,34 @@ def timeout_widget_api(self, Devices, DeviceId_, timeout_value): for unit in list(Devices): if Devices[ unit ].DeviceID == DeviceId_: timeout_legacy_device_unit_api(self, Devices, DeviceId_, unit, timeout_value) - - + + def timeout_legacy_device_unit_api(self, Devices, DeviceId_, Unit_, timeout_value): """ TimedOut one Device widget """ - + self.log.logging("AbstractDz", "Debug", f"timeout_legacy_device_unit_api: {DeviceId_} {Unit_} {timeout_value}") if _is_meter_widget( self, Devices, DeviceId_, Unit_): return - + _nValue, _sValue = domo_read_nValue_sValue(self, Devices, DeviceId_, Unit_) - _TimedOut = domo_read_TimedOut( self, Devices, DeviceId_, ) - + _TimedOut = domo_read_legacy_TimedOut( self, Devices, DeviceId_, Unit_ ) + _Name = domo_read_Name( self, Devices, DeviceId_, Unit_, ) + self.log.logging("Widget", "Debug", "timeout_legacy_device_unit_api unit %s -> %s from %s:%s %s" % ( - Devices[Unit_].Name, bool(timeout_value), _nValue, _sValue, Devices[Unit_].TimedOut)) - - if _TimedOut != timeout_value: - # Update is required - if timeout_value == 1 and self.pluginconf.pluginConf["deviceOffWhenTimeOut"]: - _switch_off_widget_due_to_timedout(self, Devices, DeviceId_, Unit_, _nValue, _sValue,) - else: - domo_update_api(self, Devices, DeviceId_, Unit_, _nValue, _sValue, TimedOut=timeout_value) + _Name, bool(timeout_value), _nValue, _sValue, bool(_TimedOut))) + + if _TimedOut == timeout_value: + return + + # Update is required + if timeout_value == 1 and self.pluginconf.pluginConf["deviceOffWhenTimeOut"]: + _switch_off_widget_due_to_timedout(self, Devices, DeviceId_, Unit_, _nValue, _sValue,) + else: + domo_update_api(self, Devices, DeviceId_, Unit_, _nValue, _sValue, TimedOut=timeout_value) def update_battery_api(self, Devices, DeviceId, battery_level): - self.log.logging("AbstractDz", "Debug", f"update_battery_api: {DeviceId} to {battery_level}") + self.log.logging( ["AbstractDz", "BatteryManagement"], "Debug", f"update_battery_api: {DeviceId} to {battery_level}") if DOMOTICZ_EXTENDED_API: if DeviceId in Devices: diff --git a/Modules/heartbeat.py b/Modules/heartbeat.py index b897cd9f5..065a3ef80 100755 --- a/Modules/heartbeat.py +++ b/Modules/heartbeat.py @@ -55,8 +55,8 @@ from Modules.schneider_wiser import schneiderRenforceent from Modules.switchSelectorWidgets import SWITCH_SELECTORS from Modules.tools import (ReArrangeMacCapaBasedOnModel, deviceconf_device, - get_device_nickname, getAttributeValue, - getListOfEpForCluster, is_hex, + get_device_nickname, get_deviceconf_parameter_value, + getAttributeValue, getListOfEpForCluster, is_hex, is_time_to_perform_work, mainPoweredDevice, night_shift_jobs, removeNwkInList) from Modules.tuya import tuya_polling @@ -648,7 +648,8 @@ def hr_process_device(self, Devices, NwkId): del self.ListOfDevices[NwkId]["pingDeviceRetry"] model = self.ListOfDevices[NwkId].get("Model", "") - enabledEndDevicePolling = bool(self.DeviceConf.get(model, {}).get("PollingEnabled", False)) + enabledEndDevicePolling = get_deviceconf_parameter_value(self, model, "PollingEnabled", return_default=False) + self.log.logging("Heartbeat", "Debug", f"Device {NwkId} Model {model} -> enabledEndDevicePolling {enabledEndDevicePolling}") check_param = self.ListOfDevices.get(NwkId, {}).get("CheckParam", False) if check_param and self.HeartbeatCount > QUIET_AFTER_START and self.ControllerLink.loadTransmit() < 5: @@ -665,16 +666,15 @@ def hr_process_device(self, Devices, NwkId): and time.time() > self.ListOfDevices[ NwkId ]["DelayBindingAtPairing"] ): # Will check only after a Command has been sent, in order to limit. - self.log.logging("Heartbeat", "Log", "check_delay_binding inHB = %s" %device_hearbeat ) + self.log.logging("Heartbeat", "Debug", "check_delay_binding inHB = %s" %device_hearbeat ) check_delay_binding( self, NwkId, model ) # Starting this point, it is ony relevant for Main Powered Devices. # Some battery based end device with ZigBee 30 use polling and can receive commands. # We should authporized them for Polling After Action, in order to get confirmation. - if not _mainPowered and not enabledEndDevicePolling: - return - process_main_powered_or_force_devices( self, NwkId, device_hearbeat, _mainPowered, enabledEndDevicePolling, model) + if _mainPowered or enabledEndDevicePolling: + process_main_powered_or_force_devices( self, NwkId, device_hearbeat, _mainPowered, enabledEndDevicePolling, model) def process_main_powered_or_force_devices(self, NwkId, device_hearbeat, _mainPowered, enabledEndDevicePolling, model): @@ -687,12 +687,11 @@ def process_main_powered_or_force_devices(self, NwkId, device_hearbeat, _mainPow rescheduleAction = rescheduleAction or pollingDeviceStatus(self, NwkId) return - rescheduleAction = ( - rescheduleAction - or DeviceCustomPolling(self, NwkId, device_hearbeat) - or pollingManufSpecificDevices(self, NwkId, device_hearbeat) - or tuya_polling(self, NwkId) - ) + rescheduleAction = ( rescheduleAction or tuya_polling(self, NwkId) ) + + rescheduleAction = ( rescheduleAction or DeviceCustomPolling(self, NwkId, device_hearbeat) ) + + rescheduleAction = ( rescheduleAction or pollingManufSpecificDevices(self, NwkId, device_hearbeat) ) _doReadAttribute = ( (self.pluginconf.pluginConf["enableReadAttributes"] or self.pluginconf.pluginConf["resetReadAttributes"]) @@ -1096,4 +1095,3 @@ def add_device_group_for_ping(self, NwkId): if target_ep: self.groupmgt.addGroupMemberShip(NwkId, target_ep, target_groupid) - \ No newline at end of file diff --git a/Modules/inRawAps.py b/Modules/inRawAps.py index dd57ea87f..2f68dfdfb 100644 --- a/Modules/inRawAps.py +++ b/Modules/inRawAps.py @@ -216,7 +216,6 @@ def inRawAps( self, Devices, srcnwkid, srcep, cluster, dstnwkid, dstep, Sqn, Glo elif Command == "04": # Get Relay status Log self.log.logging( "inRawAPS", "Debug", "inRawAps - Cluster 0201 Command 04 (Get Relay status Log) Data %s" %Data) - return if "Manufacturer" not in self.ListOfDevices[srcnwkid]: return diff --git a/Modules/occupancy_settings.py b/Modules/occupancy_settings.py index 4986705f8..bda1009f6 100644 --- a/Modules/occupancy_settings.py +++ b/Modules/occupancy_settings.py @@ -11,6 +11,7 @@ # SPDX-License-Identifier: GPL-3.0 license from DevicesModules.custom_sonoff import is_sonoff_device +from DevicesModules.custom_sunricher import is_sunricher_device from Modules.basicOutputs import write_attribute from Modules.develco import is_develco_device from Modules.philips import (is_philips_device, @@ -206,6 +207,9 @@ def common_PIROccupiedToUnoccupiedDelay(self, nwkid, delay): elif is_develco_device(self, nwkid): ListOfEp = ["22", "28", "29"] + elif is_sunricher_device(self, nwkid): + ListOfEp = ["01",] + else: ListOfEp = getListOfEpForCluster(self, nwkid, OCCUPANCY_CLUSTER_ID) diff --git a/Modules/pairingProcess.py b/Modules/pairingProcess.py index 3a6d69c40..962c2aedc 100644 --- a/Modules/pairingProcess.py +++ b/Modules/pairingProcess.py @@ -46,7 +46,8 @@ get_deviceconf_parameter_value, getListOfEpForCluster, is_fake_ep) from Modules.tuya import (tuya_cmd_ts004F, tuya_command_f0, - tuya_lighting_color_control, tuya_registration) + tuya_lighting_color_control, tuya_polling, + tuya_registration) from Modules.tuyaConst import TUYA_eTRV_MODEL from Modules.tuyaSiren import tuya_sirene_registration from Modules.tuyaTools import tuya_TS0121_registration @@ -146,7 +147,7 @@ def do_we_have_key_clusters( self, NWKID ): return False for ep in list(self.ListOfDevices[NWKID]['Ep']): for cluster in list(self.ListOfDevices[NWKID]['Ep'][ ep ]): - self.log.logging("Pairing", "Log", " . Checking %s on ep %s" %( cluster, ep)) + self.log.logging("Pairing", "Debug", " . Checking %s on ep %s" %( cluster, ep)) if cluster in CLUSTER_TO_TYPE: return True return False @@ -407,7 +408,7 @@ def zigbee_provision_device(self, Devices, NWKID, RIA, status): modelName = self.ListOfDevices[NWKID]["Model"] if "Model" in self.ListOfDevices[NWKID] else "" if modelName in ("TS004F",): - self.log.logging("Pairing", "Log", "Tuya TS004F registration needed") + self.log.logging("Pairing", "Debug", "Tuya TS004F registration needed") if "Param" in self.ListOfDevices[NWKID] and "TS004FMode" in self.ListOfDevices[NWKID]["Param"]: tuya_cmd_ts004F(self, NWKID, self.ListOfDevices[NWKID]["Param"]["TS004FMode" ]) @@ -529,7 +530,7 @@ def delay_binding_and_reporting(self, Nwkid): if _model in self.DeviceConf and "DelayBindingAtPairing" in self.DeviceConf[_model] and self.DeviceConf[_model]["DelayBindingAtPairing"]: self.ListOfDevices[ Nwkid ]["DelayBindingAtPairing"] = int(( time.time() + int(self.DeviceConf[_model]["DelayBindingAtPairing"]))) - self.log.logging("Pairing", "Log", "binding_needed_clusters_with_zigate %s Skip Binding due to >DelayBindingAtPairing<" % (Nwkid)) + self.log.logging("Pairing", "Debug", "binding_needed_clusters_with_zigate %s Skip Binding due to >DelayBindingAtPairing<" % (Nwkid)) return True return False @@ -623,56 +624,64 @@ def handle_device_specific_needs(self, Devices, NWKID): if "Model" not in self.ListOfDevices[NWKID]: return + device_model = self.ListOfDevices[NWKID]["Model"] # Do the Magic Read Attributes - if get_deviceconf_parameter_value(self, self.ListOfDevices[NWKID]["Model"], "TUYA_MAGIC_READ_ATTRIBUTES", return_default=False): + if get_deviceconf_parameter_value(self, device_model, "TUYA_MAGIC_READ_ATTRIBUTES", return_default=False): ReadAttributeRequest_0000_for_tuya( self, NWKID) # Tuya_regitration ? - tuya_registration_parameter = get_deviceconf_parameter_value(self, self.ListOfDevices[NWKID]["Model"], "TUYA_REGISTRATION", return_default=None) - ty_data_request = get_deviceconf_parameter_value(self, self.ListOfDevices[NWKID]["Model"], "TUYA_RESET_CMD", return_default=False) + tuya_registration_parameter = get_deviceconf_parameter_value(self, device_model, "TUYA_REGISTRATION", return_default=None) + tuya_data_request = get_deviceconf_parameter_value(self, device_model, "TUYA_RESET_CMD", return_default=False) + tuya_data_request_polling = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST_POLLING", return_default=False) + + self.log.logging("Pairing", "Debug", f"handle_device_specific_needs for {NWKID} tuya_registration_parameter: {tuya_registration_parameter} tuya_data_request: {tuya_data_request} tuya_data_request_polling: {tuya_data_request_polling}") + # In case of Schneider Wiser, let's do the Registration Process MsgIEEE = self.ListOfDevices[NWKID]["IEEE"] - if self.ListOfDevices[NWKID]["Model"] in ("Wiser2-Thermostat",): + if device_model in ("Wiser2-Thermostat",): wiser_home_lockout_thermostat(self, NWKID, 0) - elif get_device_config_param( self, NWKID, "AqaraMultiClick"): + if get_device_config_param( self, NWKID, "AqaraMultiClick"): enable_click_mode_aqara( self, NWKID) - elif ( MsgIEEE[: PREFIX_MAC_LEN] in PREFIX_MACADDR_WIZER_LEGACY and WISER_LEGACY_MODEL_NAME_PREFIX in self.ListOfDevices[NWKID]["Model"] ): + if ( MsgIEEE[: PREFIX_MAC_LEN] in PREFIX_MACADDR_WIZER_LEGACY and WISER_LEGACY_MODEL_NAME_PREFIX in device_model ): self.log.logging("Pairing", "Debug", "Wiser Legacy registration needed for %s" %NWKID) schneider_wiser_registration(self, Devices, NWKID) - elif self.ListOfDevices[NWKID]["Model"] in ( "AC201A", "AC211", "AC221", "CAC221" ): + if device_model in ( "AC201A", "AC211", "AC221", "CAC221" ): self.log.logging("Pairing", "Debug", "CasaIA registration needed") casaia_pairing(self, NWKID) - elif self.ListOfDevices[NWKID]["Model"] in ("TS0601-sirene",): + if device_model in ("TS0601-sirene",): self.log.logging("Pairing", "Debug", "Tuya Sirene registration needed") tuya_sirene_registration(self, NWKID) - elif self.ListOfDevices[NWKID]["Model"] in (TUYA_eTRV_MODEL): + if device_model in (TUYA_eTRV_MODEL): self.log.logging("Pairing", "Debug", "Tuya eTRV registration needed") - tuya_eTRV_registration(self, NWKID, ty_data_request=True) + tuya_eTRV_registration(self, NWKID, tuya_data_request=True) - elif tuya_registration_parameter: - tuya_registration(self, NWKID, ty_data_request=ty_data_request, parkside=False, tuya_registration_value=tuya_registration_parameter) - - elif self.ListOfDevices[NWKID]["Model"] in ("TS0121", "TS0002_relay_switch", "TS0002_relay_switch"): + if tuya_registration_parameter: + tuya_registration(self, NWKID, ty_data_request=tuya_data_request, parkside=False, tuya_registration_value=tuya_registration_parameter) + + if device_model in ("TS0121", "TS0002_relay_switch", "TS0002_relay_switch"): self.log.logging("Pairing", "Debug", "Tuya TS0121 registration needed") tuya_TS0121_registration(self, NWKID) - elif self.ListOfDevices[NWKID]["Model"] in ("TS004F", "TS004F-_TZ3000_xabckq1v"): - self.log.logging("Pairing", "Log", "Tuya TS004F registration needed") + if device_model in ("TS004F", "TS004F-_TZ3000_xabckq1v"): + self.log.logging("Pairing", "Debug", "Tuya TS004F registration needed") if "Param" in self.ListOfDevices[NWKID] and "TS004FMode" in self.ListOfDevices[NWKID]["Param"]: tuya_cmd_ts004F(self, NWKID, self.ListOfDevices[NWKID]["Param"]["TS004FMode" ]) ReadAttributeReq( self, NWKID, ZIGATE_EP, "01", "0006", [ 0x8004 ], ackIsDisabled=False, checkTime=False, ) - elif self.ListOfDevices[NWKID]["Model"] in ( "TS0222", "TS0002_relay_switch", "TS0003_relay_switch", 'TS0601-motion'): + if device_model in ( "TS0222", "TS0002_relay_switch", "TS0003_relay_switch", 'TS0601-motion'): tuya_command_f0( self, NWKID ) + if tuya_data_request_polling: + self.log.logging("Pairing", "Debug", "Tuya Tuya Polling requested") + tuya_polling(self, NWKID) - elif self.ListOfDevices[NWKID]["Model"] in ( + if device_model in ( "TS0601-Energy", "TS0601-switch", "TS0601-2Gangs-switch", @@ -687,18 +696,18 @@ def handle_device_specific_needs(self, Devices, NWKID): self.log.logging("Pairing", "Debug", "Tuya general registration needed") tuya_registration(self, NWKID, ty_data_request=True) - elif self.ListOfDevices[NWKID]["Model"] in ("TS0601-Parkside-Watering-Timer", "TS0601-_TZE200_nklqjk62"): + if device_model in ("TS0601-Parkside-Watering-Timer", "TS0601-_TZE200_nklqjk62", ): self.log.logging("Pairing", "Debug", "Tuya Water Sensor Parkside registration needed") tuya_registration(self, NWKID, ty_data_request=True, parkside=True) - elif self.ListOfDevices[NWKID]["Model"] in ( "TS0216", "TY0A01", ): + if device_model in ( "TS0216", "TY0A01", ): # Do just the registration tuya_registration(self, NWKID ) - elif self.ListOfDevices[NWKID]["Model"] == "SPZB0001": + if device_model == "SPZB0001": thermostat_Calibration(self, NWKID, 0x00) - elif self.ListOfDevices[NWKID]["Model"] == "lumi.remote.b28ac1": + if device_model == "lumi.remote.b28ac1": enable_click_mode_aqara( self, NWKID ) enableOppleSwitch( self, NWKID ) @@ -707,13 +716,15 @@ def handle_device_specific_needs(self, Devices, NWKID): if get_deviceconf_parameter_value(self, self.ListOfDevices[NWKID]["Model"], "LightingColorControl", return_default=None): tuya_lighting_color_control(self, NWKID) - + + def scan_device_for_group_memebership(self, NWKID): for ep in self.ListOfDevices[NWKID]["Ep"]: if "0004" in self.ListOfDevices[NWKID]["Ep"][ep] and self.groupmgt: self.groupmgt.ScanDevicesForGroupMemberShip( [ NWKID, ] ) break + def request_list_of_attributes(self, NWKID): for iterEp in self.ListOfDevices[NWKID]["Ep"]: self.log.logging("Pairing", "Debug", "looking for List of Attributes ep: %s" % iterEp) diff --git a/Modules/paramDevice.py b/Modules/paramDevice.py index b5863dc7c..e2a212ea2 100644 --- a/Modules/paramDevice.py +++ b/Modules/paramDevice.py @@ -12,6 +12,7 @@ from DevicesModules.custom_sonoff import SONOFF_DEVICE_PARAMETERS +from DevicesModules.custom_sunricher import SUNRICHER_DEVICE_PARAMETERS from Modules.ballast_settings import BALLAST_DEVICE_PARAMETERS from Modules.danfoss import DANFOSS_DEVICE_PARAMETERS from Modules.ias_settings import IAS_DEVICE_PARAMETERS @@ -47,6 +48,8 @@ def initialize_device_settings(self): self.device_settings.update(SONOFF_DEVICE_PARAMETERS) + self.device_settings.update(SUNRICHER_DEVICE_PARAMETERS) + self.device_settings.update(TUYA_DEVICE_PARAMETERS) self.device_settings.update(TUYA_TS011F_DEVICE_PARAMETERS) self.device_settings.update(TUYA_TRV_DEVICE_PARAMETERS) @@ -73,4 +76,4 @@ def sanity_check_of_param(self, NwkId): self.device_settings[param](self, NwkId, value) elif "callable" in self.device_settings[param]: - self.device_settings[param]["callable"](self, NwkId, value) \ No newline at end of file + self.device_settings[param]["callable"](self, NwkId, value) diff --git a/Modules/pluginHelpers.py b/Modules/pluginHelpers.py index bed9c6abc..e4659f832 100644 --- a/Modules/pluginHelpers.py +++ b/Modules/pluginHelpers.py @@ -21,12 +21,6 @@ from Modules.tools import how_many_devices from Modules.domoticzAbstractLayer import domoticz_error_api -MODULES_VERSION = { - "zigpy": "0.64.0", - "zigpy_znp": "0.12.1", - "zigpy_deconz": "0.23.1", - "bellows": "0.38.4", - } def networksize_update(self): self.log.logging("Plugin", "Debug", "Devices size has changed , let's write ListOfDevices on disk") @@ -121,7 +115,8 @@ def check_python_modules_version(self): if self.pluginconf.pluginConf["internetAccess"]: return True - for module, expected_version in MODULES_VERSION.items(): + zigpy_modules_version = parse_constraints(self.pluginParameters["HomeFolder"]) + for module, expected_version in zigpy_modules_version.items(): current_version = importlib.metadata.version(module) if current_version != expected_version: self.log.logging("Plugin", "Error", "The Python module %s version %s loaded is not compatible. Expected version: %s" % ( @@ -133,7 +128,7 @@ def check_python_modules_version(self): def check_requirements(home_folder): - requirements_file = Path(home_folder) / "requirements.txt" + requirements_file = Path(home_folder) / "constraints.txt" Domoticz.Status("Checking Python modules %s" % requirements_file) with open(requirements_file, 'r') as file: @@ -141,44 +136,50 @@ def check_requirements(home_folder): for req_str in requirements_list: req_str = req_str.strip() - if req_str == '-c constraints.txt': - continue package = re.split(r'[<>!=]+', req_str)[0].strip() version = None try: installed_version = importlib.metadata.version(package) + version = None if '==' in req_str: version = re.split('==', req_str)[1].strip() if installed_version != version: - raise importlib.metadata.PackageNotFoundError + python_module_with_wrong_version( req_str, version, installed_version) + return True elif '>=' in req_str: version = re.split('>=', req_str)[1].strip() if installed_version < version: - raise importlib.metadata.PackageNotFoundError + python_module_with_wrong_version( req_str, version, installed_version) + return True elif '<=' in req_str: version = re.split('<=', req_str)[1].strip() if installed_version > version: - raise importlib.metadata.PackageNotFoundError + python_module_with_wrong_version( req_str, version, installed_version) + return True - except importlib.metadata.PackageNotFoundError: - Domoticz.Error(f"Looks like {req_str} Python module is not installed or does not meet the required version. Requires {version}, Installed {installed_version}. " - f"Make sure to install the required Python3 module with the correct version.") - Domoticz.Error("Use the command:") - Domoticz.Error("sudo python3 -m pip install -r requirements.txt --upgrade") + except importlib.metadata.PackageNotFoundError as e: + Domoticz.Error(f"An unexpected error occurred while checking {req_str} - {e}") return True - except importlib.metadata.MetadataError: - Domoticz.Error(f"An unexpected error occurred while checking {req_str}") + except importlib.metadata.MetadataError as e: + Domoticz.Error(f"An unexpected error occurred while checking {req_str} - {e}") return True except Exception as e: Domoticz.Error(f"An unexpected error occurred: {e}") return True + Domoticz.Status(f" - {req_str} version required {version} installed {installed_version}") return False +def python_module_with_wrong_version( req_str, version, installed_version): + Domoticz.Error(f"Looks like {req_str} Python module is not installed or does not meet the required version. Requires {version}, Installed {installed_version}." + f"Make sure to install the required Python3 module with the correct version.") + Domoticz.Error("Use the command:") + Domoticz.Error("sudo python3 -m pip install -r requirements.txt --upgrade") + def list_all_modules_loaded(self): # Get a list of modules imported by the main script @@ -197,3 +198,37 @@ def list_all_modules_loaded(self): version = installed_packages.get(module_name, "Not installed") self.log.logging("Plugin", "Log", f"{module_name}: {version}") self.log.logging("Plugin", "Log", "=============================") + + +def parse_constraints(home_folder): + modules_version = { + "zigpy": "", + "zigpy_znp": "", + "zigpy_deconz": "", + "bellows": "" + } + + constraints_file = Path(home_folder) / "constraints.txt.txt" + with open(constraints_file, 'r') as file: + for line in file: + # Remove leading/trailing whitespace and newlines + line = line.strip() + + # Split line into module name and version + if '==' in line: + module, version = line.split('==') + elif '>=' in line: + module, version = line.split('>=') + elif '<=' in line: + module, version = line.split('<=') + else: + continue + + # Check if the module is one we are interested in + if module in modules_version: + modules_version[module] = version + + # Remove any entries where version is still empty + modules_version = {k: v for k, v in modules_version.items() if v} + + return modules_version diff --git a/Modules/pluginModels.py b/Modules/pluginModels.py index d84372004..b4c204569 100644 --- a/Modules/pluginModels.py +++ b/Modules/pluginModels.py @@ -36,29 +36,44 @@ def plugin_self_identifier( self, model, manufacturer): return self.ModelManufMapping[ ( model, manufacturer ) ] return None + def check_found_plugin_model( self, model, manufacturer_name=None, manufacturer_code=None, device_id=None): - self.log.logging( "Pairing", "Debug", "check_found_plugin_model - %s %s %s %s" % ( - model, manufacturer_name, manufacturer_code, device_id)) + self.log.logging( "Pairing", "Debug", f"check_found_plugin_model - model={model}, manufacturer_name={manufacturer_name}, manufacturer_code={manufacturer_code}, device_id={device_id}") + + device_id = None if device_id == {} else device_id + manufacturer_name = None if manufacturer_name == {} else manufacturer_name + manufacturer_code = None if manufacturer_code == {} else manufacturer_code # Let's check if for x in PLUGIN_MODELS_MATRIX: - if "Model" in x and model not in x["Model"]: - continue - if ( - ( "Manufacturer" in x and x["Manufacturer"] and manufacturer_name not in x["Manufacturer"] ) - or ( "ManufId" in x and x["ManufId"] and manufacturer_code not in x["ManufId"]) - or ( "DeviceID" in x and x["DeviceID"] and device_id not in x["DeviceID"] ) - ): - continue - - self.log.logging( "Pairing", "Debug", "check_found_plugin_model - Found %s" % x) - - if "PluginModelName" in x: - self.log.logging( "Pairing", "Debug", "check_found_plugin_model - return %s" % ( - x["PluginModelName"])) - - return x["PluginModelName"] - + try: + if "Model" in x and model not in x["Model"]: + continue + + if ( + ( "Manufacturer" in x and x["Manufacturer"] and manufacturer_name and manufacturer_name not in x["Manufacturer"] ) + or ( "ManufId" in x and x["ManufId"] and manufacturer_code and manufacturer_code not in x["ManufId"]) + or ( "DeviceID" in x and x["DeviceID"] and device_id and device_id not in x["DeviceID"] ) + ): + continue + + self.log.logging( "Pairing", "Debug", "check_found_plugin_model - Found %s" % x) + + if "PluginModelName" in x: + self.log.logging( "Pairing", "Debug", "check_found_plugin_model - return %s" % (x["PluginModelName"])) + return x["PluginModelName"] + + except Exception as errno: + error_message = f"kindly report this error{errno} find in module check_found_plugin_model" + _context = { + "Model": model, + "Manufacturer Name": manufacturer_name, + "Manufacture Code": manufacturer_code, + "DeviceID": device_id, + "Current Model Conf": x + } + self.log.logging( "Pairing", "Error", error_message, context=_context) + return model diff --git a/Modules/profalux.py b/Modules/profalux.py index 00144a8c3..1b97e27d2 100644 --- a/Modules/profalux.py +++ b/Modules/profalux.py @@ -220,48 +220,50 @@ def profalux_MoveWithOnOff(self, nwkid, OnOff): def profalux_MoveToLiftAndTilt(self, nwkid, level=None, tilt=None): + def getLevel(self, nwkid): - # Let's check if we can get the Level from Attribute + # Initialize level to None level = None - if ( - "01" in self.ListOfDevices[nwkid]["Ep"] - and "0008" in self.ListOfDevices[nwkid]["Ep"]["01"] - and "0000" in self.ListOfDevices[nwkid]["Ep"]["01"]["0008"] - ): - if isinstance(self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"], str ): - level = int(self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"], 16) - else: - level = self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"] + # Retrieve nested dictionary values + ep = self.ListOfDevices.get(nwkid, {}).get("Ep", {}).get("01", {}).get("0008", {}) + + # Check and convert the level if available + level_value = ep.get("0000") + if level_value is not None: + level = int(level_value, 16) if isinstance(level_value, str) else level_value return level def getTilt(self, nwkid): tilt = 45 - if "Param" in self.ListOfDevices[nwkid] and "profaluxOrientBSO" in self.ListOfDevices[nwkid]["Param"]: - tilt = self.ListOfDevices[nwkid]["Param"]["profaluxOrientBSO"] - - # Let's check if we can get the Tilt from Attribute - if ( - "01" in self.ListOfDevices[nwkid]["Ep"] - and "fc21" in self.ListOfDevices[nwkid]["Ep"]["01"] - and "0001" in self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"] - ): - tilt = int(self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"]["0001"], 16) - return tilt + + device = self.ListOfDevices.get(nwkid, {}) + param = device.get("Param", {}) + if "profaluxOrientBSO" in param: + tilt = param["profaluxOrientBSO"] + + ep = device.get("Ep", {}).get("01", {}).get("fc21", {}) + tilt_value = ep.get("0001") + if tilt_value is not None and isinstance(tilt_value, str): + tilt_value = int(tilt_value, 16) + + return tilt_value + def setLevel(self, nwkid, level): - if "01" not in self.ListOfDevices[nwkid]["Ep"]: - self.ListOfDevices[nwkid]["Ep"]["01"] = {} - if "0008" not in self.ListOfDevices[nwkid]["Ep"]["01"]: - self.ListOfDevices[nwkid]["Ep"]["01"]["0008"] = {} - self.ListOfDevices[nwkid]["Ep"]["01"]["0008"]["0000"] = level + device = self.ListOfDevices[nwkid] + ep = device.setdefault("Ep", {}) + ep_01 = ep.setdefault("01", {}) + ep_01_0008 = ep_01.setdefault("0008", {}) + ep_01_0008["0000"] = level + def setTilt(self, nwkid, tilt): - if "01" not in self.ListOfDevices[nwkid]["Ep"]: - self.ListOfDevices[nwkid]["Ep"]["01"] = {} - if "fc21" not in self.ListOfDevices[nwkid]["Ep"]["01"]: - self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"] = {} - self.ListOfDevices[nwkid]["Ep"]["01"]["fc21"]["0001"] = "%02x" % tilt + device = self.ListOfDevices[nwkid] + ep = device.setdefault("Ep", {}) + ep_01 = ep.setdefault("01", {}) + ep_fc21 = ep_01.setdefault("fc21", {}) + ep_fc21["0001"] = f"{tilt:02x}" # Begin self.log.logging( diff --git a/Modules/readAttributes.py b/Modules/readAttributes.py index 7893a0086..9920351bb 100644 --- a/Modules/readAttributes.py +++ b/Modules/readAttributes.py @@ -313,19 +313,7 @@ def ping_device_with_read_attribute(self, key): for EPout in ListOfEp: check_datastruct(self, "ReadAttributes", key, EPout, PING_CLUSTER) - i_sqn = read_attribute( - self, - key, - ZIGATE_EP, - EPout, - PING_CLUSTER, - "00", - "00", - "0000", - "%02x" % (0x01), - PING_CLUSTER_ATTRIBUTE, - ackIsDisabled=False, - ) + i_sqn = read_attribute( self, key, ZIGATE_EP, EPout, PING_CLUSTER, "00", "00", "0000", "%02x" % (0x01), PING_CLUSTER_ATTRIBUTE, ackIsDisabled=False, ) set_isqn_datastruct(self, "ReadAttributes", key, EPout, PING_CLUSTER, PING_CLUSTER_ATTRIBUTE, i_sqn) # Let's ping only 1 EndPoint diff --git a/Modules/readClusters.py b/Modules/readClusters.py index b711f8872..3b25caa89 100644 --- a/Modules/readClusters.py +++ b/Modules/readClusters.py @@ -21,7 +21,6 @@ # import time import struct from time import time -from Modules.batterieManagement import UpdateBatteryAttribute from Modules.domoMaj import MajDomoDevice from Modules.domoTools import timedOutDevice from Modules.ikeaTradfri import ikea_air_purifier_cluster @@ -29,7 +28,6 @@ decode_vibrAngle, readLumiLock, readXiaomiCluster, store_lumi_attribute) from Modules.philips import philips_dimmer_switch -from Modules.pluginModels import check_found_plugin_model from Modules.readZclClusters import (is_cluster_zcl_config_available, process_cluster_attribute_response) from Modules.schneider_wiser import (receiving_heatingdemand_attribute, diff --git a/Modules/readZclClusters.py b/Modules/readZclClusters.py index ac85a40f5..013e73488 100644 --- a/Modules/readZclClusters.py +++ b/Modules/readZclClusters.py @@ -20,7 +20,9 @@ from Modules.batterieManagement import UpdateBatteryAttribute from Modules.domoMaj import MajDomoDevice from Modules.tools import (checkAndStoreAttributeValue, - get_device_config_param, getAttributeValue) + get_device_config_param, getAttributeValue, + store_battery_percentage_time_stamp, + store_battery_voltage_time_stamp) from Modules.zclClusterHelpers import (decoding_attribute_data, handle_model_name) @@ -44,6 +46,8 @@ STORE_SPECIFIC_PLACE_LVL3 = "SpecifStoragelvl3" UPDATE_DOMO_DEVICE = "upd_domo_device" UPDATE_BATTERY = "update_battery" +UPDATE_BATTERY_VOLTAGE = "update_battery_voltage" +UPDATE_BATTERY_PERCENTAGE = "update_battery_percentage" ACTIONS_TO_FUNCTIONS = { CHECK_AND_STORE: checkAndStoreAttributeValue, @@ -145,8 +149,12 @@ def process_cluster_attribute_response( self, Devices, MsgSQN, MsgSrcAddr, MsgSr elif data_action == CHECK_AND_STORE: checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, value) - elif data_action == UPDATE_BATTERY: + elif data_action in ( UPDATE_BATTERY, UPDATE_BATTERY_VOLTAGE, UPDATE_BATTERY_PERCENTAGE): UpdateBatteryAttribute(self, Devices, MsgSrcAddr, MsgSrcEp) + if data_action == UPDATE_BATTERY_PERCENTAGE: + store_battery_percentage_time_stamp( self, MsgSrcAddr) + elif data_action == UPDATE_BATTERY_VOLTAGE: + store_battery_voltage_time_stamp( self, MsgSrcAddr) elif data_action == UPDATE_DOMO_DEVICE and majdomodevice_possiblevalues( self, MsgSrcEp, MsgClusterId, MsgAttrID, device_model, value ): action_majdomodevice( self, Devices, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, device_model, value ) diff --git a/Modules/schneider_wiser.py b/Modules/schneider_wiser.py index a9991ac2e..2ab5b9430 100755 --- a/Modules/schneider_wiser.py +++ b/Modules/schneider_wiser.py @@ -1453,7 +1453,7 @@ def importSchneiderZoning(self): SCHNEIDER_ZONING = "schneider_zoning.json" - self.SchneiderZoningFilename = self.pluginconf.pluginConf["pluginConfig"] + SCHNEIDER_ZONING + self.SchneiderZoningFilename = self.pluginconf.pluginConf["pluginConfig"] + os.sep + SCHNEIDER_ZONING if not os.path.isfile(self.SchneiderZoningFilename): self.log.logging("Schneider", "Debug", f"importSchneiderZoning - Nothing to import from {self.SchneiderZoningFilename}") diff --git a/Modules/switchSelectorWidgets.py b/Modules/switchSelectorWidgets.py index 2259d283b..e947aaaba 100644 --- a/Modules/switchSelectorWidgets.py +++ b/Modules/switchSelectorWidgets.py @@ -594,6 +594,34 @@ "01": (1, "On"), "ForceUpdate": False }, + "PollingControl": { + "00": (0, "00"), + "01": (1, "10"), + "02": (2, "20"), + "ForceUpdate": False, + "SelectorStyle": 1, + "LevelNames": "Off|Slow Polling|Fast Polling", + "Language": { + "fr-FR": { + "LevelNames": "Arrêt|Mesures normale|Mesures rapides" + } + } + }, + "PollingControlV2": { + "00": (0, "00"), # Off + "01": (3, "10"), # "2/day" -> 43200 secondes ( 12 heures) + "02": (4, "20"), # "20/day" -> 4320 secondes ( 1h 12 minutes) + "03": (5, "30"), # "96/day" -> 900 secondes ( 15 minutes) + "05": (2, "40"), # Fast Polling, Force polling to every 15s + "ForceUpdate": False, + "SelectorStyle": 1, + "LevelNames": "Off|2x/day|20x/day|96x/day|Fast Polling", + "Language": { + "fr-FR": { + "LevelNames": "Arrêt|2x/day|20x/day|96x/day|Mesures rapides" + } + } + }, "SOS": { "01": (1, "On"), "ForceUpdate": True @@ -606,7 +634,9 @@ }, "Switch": { "00": (0, "Off"), + 0: (0, "Off"), "01": (1, "On"), + 1: (1, "On"), "ForceUpdate": False }, "SwitchAQ2": { @@ -814,7 +844,7 @@ "LevelNames": "Off|Auto|Manual|Temp Hand|Holidays", "Language": { "fr-FR": { - "LevelNames": "Arrêt|Auto|Manuel" + "LevelNames": "Arrêt|Auto|Manuel|Temp Hand|Vacances" } } }, @@ -862,6 +892,24 @@ } } }, + "ThermoMode_8": { + 0: (0, "Off"), + 1: (1, "10"), + 2: (2, "20"), + 3: (3, "30"), + 4: (4, "40"), + 5: (5, "50"), + "ForceUpdate": True, + "OffHidden": True, + "SelectorStyle": 1, + "LevelNames": "Off|Manual|Auto|Eco|Confort|Holidays", + "Language": { + "fr-FR": { + "LevelNames": "Arrêt|Manuel|Auto|Eco|Confort|Vacances" + } + } + }, + "ThermoOnOff": { 0: (0, "Off"), 1: (1, "On"), diff --git a/Modules/tools.py b/Modules/tools.py index 6075b4d24..99563c4da 100644 --- a/Modules/tools.py +++ b/Modules/tools.py @@ -53,6 +53,8 @@ def str_round(value, n): return "{:.{n}f}".format(value, n=int(n)) def voltage2batteryP(voltage, volt_max, volt_min): + if isinstance( voltage, str): + voltage = int(voltage) if voltage > volt_max: ValueBattery = 100 @@ -433,24 +435,31 @@ def timeStamped(self, key, Type): # Used by zcl/zdpRawCommands def get_and_inc_ZDP_SQN(self, key): return get_and_increment_generic_SQN(self, key, "ZDPSQN") - + + def get_and_inc_ZCL_SQN(self, key): return get_and_increment_generic_SQN(self, key, "ZCLSQN") - + + +def get_and_inc_TUYA_POLLING_SQN(self, key): + return get_and_increment_generic_SQN(self, key, "TUYA_POLLING_SQN") + + def get_and_increment_generic_SQN(self, nwkid, sqn_type): if nwkid not in self.ListOfDevices: return "%02x" %0x00 + if sqn_type not in self.ListOfDevices[nwkid]: self.ListOfDevices[nwkid][ sqn_type ] = "%02x" %0x00 return self.ListOfDevices[nwkid][ sqn_type ] - + if self.ListOfDevices[nwkid][ sqn_type ] in ( '', {}): self.ListOfDevices[nwkid][ sqn_type ] = "%02x" %0x00 return self.ListOfDevices[nwkid][ sqn_type ] self.ListOfDevices[nwkid][ sqn_type ] = "%02x" %( ( int(self.ListOfDevices[nwkid][ sqn_type ],16) + 1) % 256) return self.ListOfDevices[nwkid][ sqn_type ] - + def updSQN(self, key, newSQN): if key in self.ListOfDevices and newSQN: @@ -1022,10 +1031,18 @@ def checkAttribute(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID): def checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, Value): - checkAttribute(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID) self.ListOfDevices[MsgSrcAddr]["Ep"][MsgSrcEp][MsgClusterId][MsgAttrID] = Value + +def store_battery_percentage_time_stamp( self, MsgSrcAddr): + self.ListOfDevices[MsgSrcAddr]["BatteryPercentage_TimeStamp"] = time.time() + + +def store_battery_voltage_time_stamp( self, MsgSrcAddr): + self.ListOfDevices[MsgSrcAddr]["BatteryVoltage_TimeStamp"] = time.time() + + def checkValidValue(self, MsgSrcAddr, AttType, Data ): if int(AttType, 16) == 0xE2 and Data == "ffffffff": return False @@ -1445,15 +1462,9 @@ def how_many_devices(self): def get_deviceconf_parameter_value(self, model, attribute, return_default=None): - """ Retreive Configuration Attribute from Config file""" + """ Retrieve Configuration Attribute from Config file""" - if model in ( '', {}): - return return_default - if model not in self.DeviceConf: - return return_default - if attribute not in self.DeviceConf[ model ]: - return return_default - return self.DeviceConf[ model ][ attribute ] + return self.DeviceConf.get(model, {}).get(attribute, return_default) def night_shift_jobs( self ): diff --git a/Modules/tuya.py b/Modules/tuya.py index 094338c58..7ce2b0335 100644 --- a/Modules/tuya.py +++ b/Modules/tuya.py @@ -27,18 +27,21 @@ from Modules.domoMaj import MajDomoDevice from Modules.domoTools import Update_Battery_Device from Modules.tools import (build_fcf, checkAndStoreAttributeValue, - get_and_inc_ZCL_SQN, get_device_config_param, + get_and_inc_ZCL_SQN, + get_device_config_param, get_deviceconf_parameter_value, is_ack_tobe_disabled, updSQN) from Modules.tuyaConst import (TUYA_MANUF_CODE, TUYA_SMART_DOOR_LOCK_MODEL, TUYA_eTRV_MODEL) from Modules.tuyaSiren import tuya_siren2_response, tuya_siren_response -from Modules.tuyaTools import (get_tuya_attribute, store_tuya_attribute, - tuya_cmd) +from Modules.tuyaTools import (get_next_tuya_transactionId, get_tuya_attribute, + store_tuya_attribute, tuya_cmd) from Modules.tuyaTRV import tuya_eTRV_response from Modules.tuyaTS011F import tuya_read_cluster_e001 from Modules.tuyaTS0601 import ts0601_response from Modules.zigateConsts import ZIGATE_EP +from Zigbee.zclDecoders import zcl_raw_default_response + # Tuya TRV Commands # https://medium.com/@dzegarra/zigbee2mqtt-how-to-add-support-for-a-new-tuya-based-device-part-2-5492707e882d @@ -54,6 +57,7 @@ # 0x04: enum8 ( 0x00-0xff) # 0x05: bitmap ( 1,2, 4 bytes) as bits + def is_tuya_switch_relay(self, nwkid): model = self.ListOfDevices[nwkid].get("Model", "") return model in ( "TS0601-switch", "TS0601-2Gangs-switch", "TS0601-Energy", ) @@ -130,7 +134,6 @@ def tuya_cmd_ts004F(self, NwkId, mode): def tuya_cmd_0x0000_0xf0(self, NwkId): - # Seen at pairing of a WGH-JLCZ02 / TS011F and TS0201 and TS0601 (MOES BRT-100) payload = "11" + get_and_inc_ZCL_SQN(self, NwkId) + "fe" @@ -138,35 +141,245 @@ def tuya_cmd_0x0000_0xf0(self, NwkId): self.log.logging("Tuya", "Debug", "tuya_cmd_0x0000_0xf0 - Nwkid: %s reset device Cmd: fe" % NwkId) +def tuya_polling_control(self, Nwkid, WidgetType, Level): + # Mapping Level to Polling modes + polling_modes = { + "PollingControl": { + 0: "Off", + 10: "Slow Polling", + 20: "Fast Polling", + }, + "PollingControlV2": { + 0: "Off", + 10: "2/day", + 20: "20/day", + 30: "96/day", + 40: "Fast Polling", + } + } + + self.log.logging("Tuya", "Log", f"tuya_polling_control - Nwkid: {Nwkid}/01 Level {Level}") + + # Set default Tuya device info and polling mode + tuya_device_info = self.ListOfDevices.setdefault(Nwkid, {}).setdefault("Tuya", {}) + if WidgetType not in polling_modes: + self.log.logging("Tuya", "Error", f"tuya_polling_control - Unexpected WidgetType {WidgetType} !!!") + return + + tuya_device_info["Polling"] = polling_modes[ WidgetType ].get(Level, tuya_device_info.get("Polling", "Normal Polling")) + + self.log.logging("Tuya", "Log", f"tuya_polling_control - Nwkid: {Nwkid}/01 Polling Mode {tuya_device_info['Polling']}") + + +def tuya_polling_values(self, nwkid, device_model, tuya_device_info): + # This is based on command 0x03, which query ALL datapoint + tuya_data_query = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST", return_default=0) + # Retrieve the polling interval configuration for TUYA_DATA_REQUEST_POLLING which query only the data point which have changed + tuya_data_request_polling = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST_POLLING", return_default=0) + + if not tuya_data_query and not tuya_data_request_polling: + return 0, 0, 0, 0, 0 + + # 3 consecutives polling by default + tuya_data_request_polling_additional = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST_POLLING_ADDITIONAL", return_default=3) + + # Each consecutive polling must be separated by 15s by default + tuya_elapse_time_consecutive_polling = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST_POLLING_CONSECUTIVE_ELAPSE", return_default=15) + + additional_polls = tuya_device_info.get("AdditionalPolls", tuya_data_request_polling_additional) + + polling_status = tuya_device_info.setdefault("Polling", "Off") + + current_battery_level = get_tuya_attribute(self, nwkid, "Battery") + if isinstance(current_battery_level, str) and current_battery_level.isdigit(): + current_battery_level = int(current_battery_level) + + # Usall default is 300s ( 5 minutes ) + if current_battery_level and current_battery_level < 30: + # TODO needs to update Widget + polling_status = "2/day" + + elif current_battery_level and current_battery_level < 50: + # TODO needs to update Widget + polling_status = "20/day" + + # Polling methods + if polling_status == "Off": + # No polling , just exit + return 0, 0, 0, 0, 0 + + elif polling_status == "Fast Polling": + # Force polling to every 15s + tuya_data_request_polling = 10 + tuya_data_query = 60 # A query ( 0x03 ) every minutes + tuya_data_request_polling_additional = 0 + tuya_elapse_time_consecutive_polling = 5 + + elif polling_status == "2/day": + # 2/jour -> 43200 secondes ( 12 heures) + tuya_data_request_polling = 43200 + tuya_data_query = 43200 # A query ( 0x03 ) every minutes + tuya_data_request_polling_additional = 0 + tuya_elapse_time_consecutive_polling = 5 + + elif polling_status == "20/day": + # 20/jours -> 4320 secondes ( 1h 12 minutes) + tuya_data_request_polling = 4320 + tuya_data_query = 4320 # A query ( 0x03 ) every minutes + tuya_data_request_polling_additional = 0 + tuya_elapse_time_consecutive_polling = 5 + + elif polling_status == "96/day": + # 96/jour -> 900 secondes ( 15 minutes) + tuya_data_request_polling = 900 + tuya_data_query = 3600 # A query ( 0x03 ) every minutes + tuya_data_request_polling_additional = 0 + tuya_elapse_time_consecutive_polling = 5 + + self.log.logging("Tuya", "Debug", f"tuya_polling - Nwkid: {nwkid}/01 tuya_data_request_polling {tuya_data_request_polling}") + self.log.logging("Tuya", "Debug", f"tuya_polling - Nwkid: {nwkid}/01 tuya_data_query {tuya_data_query}") + self.log.logging("Tuya", "Debug", f"tuya_polling - Nwkid: {nwkid}/01 tuya_data_request_polling_additional {tuya_data_request_polling_additional}") + self.log.logging("Tuya", "Debug", f"tuya_polling - Nwkid: {nwkid}/01 tuya_elapse_time_consecutive_polling {tuya_elapse_time_consecutive_polling}") + + return tuya_data_query, tuya_data_request_polling, tuya_data_request_polling_additional, tuya_elapse_time_consecutive_polling, additional_polls + + def tuya_polling(self, nwkid): """Some Tuya devices, requirea specific polling""" + device_model = self.ListOfDevices.get(nwkid, {}).get("Model") if device_model is None: - return + return False - tuya_data_request_polling = get_deviceconf_parameter_value(self, device_model, "TUYA_DATA_REQUEST_POLLING", return_default=0) + # Retrieve the device information + tuya_device_info = self.ListOfDevices.setdefault(nwkid, {}).setdefault("Tuya", {}) + + tuya_data_query, tuya_data_request_polling, tuya_data_request_polling_additional, tuya_elapse_time_consecutive_polling,additional_polls = tuya_polling_values(self, nwkid, device_model, tuya_device_info) + + if not tuya_data_request_polling and not tuya_data_query: + return False + + self.log.logging("Tuya", "Debug", f"tuya_polling - Nwkid: {nwkid}/01 AdditionalPolls {additional_polls}") - if tuya_data_request_polling: - device_last_poll = self.ListOfDevices.get(nwkid, {}).get("Tuya", {}).get("LastTuyaDataRequest", 0) - if device_last_poll > (time.time() + tuya_data_request_polling): - self.log.logging("Tuya", "Log", f"tuya_data_request_polling - Nwkid: {nwkid}/01 time for polling {tuya_data_request_polling}") - tuya_data_request(self, nwkid, "01") + if tuya_data_query and should_poll(self, nwkid, tuya_device_info, "LastTuyaDataQuery", polling_interval=tuya_data_query): + self.log.logging("Tuya", "Debug", f"tuya_polling - tuya_data_request 0x03 Nwkid: {nwkid}/01 time for polling") + tuya_data_request(self, nwkid, "01") + return True + if tuya_data_request_polling and should_poll(self, nwkid, tuya_device_info, "LastTuyaDataRequest", polling_interval=tuya_data_request_polling, additional_polls=additional_polls, tuya_data_request_polling_additional=tuya_data_request_polling_additional, tuya_elapse_time_consecutive_polling=tuya_elapse_time_consecutive_polling): + # If the current time is greater than or equal to the next polling time, it will proceed with polling + self.log.logging("Tuya", "Log", f"tuya_polling - tuya_data_request_poll 0x00 dp 69 dt 02 - Nwkid: {nwkid}/01 time for polling with {additional_polls}") + tuya_data_request_poll(self, nwkid, "01") + return True + + if get_tuya_attribute(self, nwkid, "backlight_level") not in ( 0, "00000000"): + self.log.logging("Tuya", "Debug", "tuya_polling - backlight_level: %s" %get_tuya_attribute(self, nwkid, "backlight_level")) + tuya_data_request_end_poll(self, nwkid, "01") + + # No polling done return False + +def should_poll(self, nwkid, tuya_device_info, tuya_last_poll_attribute, polling_interval, additional_polls=0, tuya_data_request_polling_additional=0, tuya_elapse_time_consecutive_polling=15): + """" Check if it is time for a poll. Because it is time, or because we have additional poll to be made.""" + + # Log the polling interval value + self.log.logging("Tuya", "Debug", f"should_poll - Nwkid: {nwkid}/01 tuya_data_request_polling {polling_interval} additional_polls: {additional_polls} tuya_data_request_polling_additional: {tuya_data_request_polling_additional} tuya_elapse_time_consecutive_polling: {tuya_elapse_time_consecutive_polling}") + + # Retrieve the last polling time and additional polls + last_poll_time = tuya_device_info.get(tuya_last_poll_attribute, 0) + + # Calculate the next polling time + next_poll_time = last_poll_time + polling_interval + consecutive_elapse_time = last_poll_time + tuya_elapse_time_consecutive_polling + + # Get the current time + current_time = int(time.time()) + + # Log the last polling time and the next polling time for comparison + self.log.logging("Tuya", "Debug", f"should_poll - Nwkid: {nwkid}/01 device_last_poll current time {current_time}") + self.log.logging("Tuya", "Debug", f" - Nwkid: {nwkid}/01 device_last_poll last_poll_time: {last_poll_time}") + self.log.logging("Tuya", "Debug", f" - Nwkid: {nwkid}/01 tuya_data_request_polling next_poll_time: {next_poll_time}") + self.log.logging("Tuya", "Debug", f" - Nwkid: {nwkid}/01 tuya_data_request_polling consecutive_elapse_time: {consecutive_elapse_time}") + + # We do the check that we do not overload and respect the consecutive_elapse_time + if current_time < consecutive_elapse_time: + # We need at least 6 secondes between each poll - so all data are correctly sent and the device is ready to take a new request + self.log.logging("Tuya", "Debug", f"should_poll - Nwkid: {nwkid}/01 skip as last request was less that {tuya_elapse_time_consecutive_polling} s ago") + return False + + # Check if the current time is less than the next polling time + if current_time < next_poll_time: + if additional_polls <= 0: + return False + + self.log.logging("Tuya", "Debug", f"should_poll - Nwkid: {nwkid}/01 additional poll {additional_polls}") + # If within additional polls window, decrement the counter and allow polling + self.ListOfDevices[nwkid]["Tuya"][ tuya_last_poll_attribute ] = current_time + self.ListOfDevices[nwkid]["Tuya"]["AdditionalPolls"] = additional_polls - 1 + return True + + # If the current time is greater than or equal to the next polling time, proceed with polling logic + # Update the last polling time and reset the additional polls counter + self.log.logging("Tuya", "Debug", f"should_poll - Nwkid: {nwkid}/01 We are entering in a new cycle") + self.ListOfDevices[nwkid]["Tuya"][ tuya_last_poll_attribute ] = current_time + self.ListOfDevices[nwkid]["Tuya"]["AdditionalPolls"] = tuya_data_request_polling_additional + + return True + + +def tuya_data_request_poll(self, nwkid, epout): + self.log.logging("Tuya", "Debug", "tuya_data_request_poll - Nwkid: %s tuya polling Cmd: 00" % nwkid) + # Cmd 0x00 - 01/46/6902/0004/00000001/ + # Cmd 0x00 - 00/d7/6902/0004/00000001/ + + sqn = get_and_inc_ZCL_SQN(self, nwkid) + cluster_frame = "11" + cmd = "00" # Command + action = "6902" + data = "00000001" + + self.log.logging("Tuya", "Debug", f"tuya_data_request_poll - Nwkid: {nwkid} epout: {epout} sqn: {sqn} cluster_frame: {cluster_frame} cmd: {cmd} action: {action} data: {data}") + tuya_cmd(self, nwkid, epout, cluster_frame, sqn, cmd, action, data, action2=None, data2=None) + + +def tuya_data_request_end_poll(self, nwkid, epout): + self.log.logging("Tuya", "Debug", "tuya_data_request_poll - Nwkid: %s tuya polling Cmd: 00" % nwkid) + # Cmd 0x00 - 01/46/6902/0004/00000001/ + # Cmd 0x00 - 00/d7/6902/0004/00000001/ + + sqn = get_and_inc_ZCL_SQN(self, nwkid) + cluster_frame = "11" + cmd = "00" # Command + action = "6902" + data = "00000000" + + self.log.logging("Tuya", "Debug", f"tuya_data_request_poll - Nwkid: {nwkid} epout: {epout} sqn: {sqn} cluster_frame: {cluster_frame} cmd: {cmd} action: {action} data: {data}") + tuya_cmd(self, nwkid, epout, cluster_frame, sqn, cmd, action, data, action2=None, data2=None) + + def tuya_data_request(self, nwkid, epout): - payload = "11" + get_and_inc_ZCL_SQN(self, nwkid) + "03" - raw_APS_request( self, nwkid, epout, "ef00", "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), ) - self.log.logging("Tuya", "Debug", "tuya_data_request - Nwkid: %s reset device Cmd: 03" % nwkid) - self.ListOfDevices.setdefault(nwkid, {}).setdefault("Model", time.time()) + # TY_DATA_QUERY + # 0x03 The gateway sends a query to the Zigbee device for all the current information. + # The query does not contain a ZCL payload. We recommend that you set a reporting policy + # on the Zigbee device to avoid reporting all data in one task. + cluster_frame = "11" + sqn = get_and_inc_ZCL_SQN(self, nwkid) + cmd = "03" # TY_DATA_QUERY + payload = cluster_frame + sqn + cmd + + self.log.logging("Tuya", "Log", f"tuya_data_request - Nwkid: {nwkid} epout: {epout} sqn: {sqn} cluster_frame: {cluster_frame} cmd: {cmd}") + raw_APS_request( self, nwkid, epout, "ef00", "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=False ) + self.log.logging("Tuya", "Debug", "tuya_data_request - Nwkid: %s TUYA_DATA_QUERY Cmd: 03 done!" % nwkid) + def callbackDeviceAwake_Tuya(self, Devices, NwkId, EndPoint, cluster): """ This is fonction is call when receiving a message from a Manufacturer battery based device. The function is called after processing the readCluster part """ - self.log.logging( "Tuya", "Log", "callbackDeviceAwake_Tuya - Nwkid: %s, EndPoint: %s cluster: %s" % (NwkId, EndPoint, cluster)) + self.log.logging( "Tuya", "Debug", "callbackDeviceAwake_Tuya - Nwkid: %s, EndPoint: %s cluster: %s" % (NwkId, EndPoint, cluster)) def tuyaReadRawAPS(self, Devices, NwkId, srcEp, ClusterID, dstNWKID, dstEP, MsgPayload): @@ -180,7 +393,7 @@ def tuyaReadRawAPS(self, Devices, NwkId, srcEp, ClusterID, dstNWKID, dstEP, MsgP if ClusterID != "ef00" or "Model" not in self.ListOfDevices[NwkId]: return - _ModelName = self.ListOfDevices[NwkId]["Model"] + _ModelName = self.ListOfDevices[NwkId].get("Model", "") if len(MsgPayload) < 6: self.log.logging("Tuya", "Debug2", "tuyaReadRawAPS - MsgPayload %s too short" % (MsgPayload), NwkId) @@ -193,7 +406,11 @@ def tuyaReadRawAPS(self, Devices, NwkId, srcEp, ClusterID, dstNWKID, dstEP, MsgP cmd = MsgPayload[4:6] # uint8 # Send a Default Response ( why might check the FCF eventually ) if self.zigbee_communication == "native" and self.FirmwareVersion and int(self.FirmwareVersion, 16) < 0x031E: - tuya_send_default_response(self, NwkId, srcEp, sqn, cmd, fcf) + #tuya_send_default_response(self, NwkId, srcEp, sqn, cmd, fcf) + tuya_default_response(self, NwkId, srcEp, ClusterID, cmd, sqn, fcf) + elif self.zigbee_communication == "zigpy" and cmd == "02" and get_deviceconf_parameter_value(self, _ModelName, "TY_DEFAULT_RESPONSE", return_default=False): + tuya_default_response(self, NwkId, srcEp, ClusterID, cmd, sqn, fcf) + # https://developer.tuya.com/en/docs/iot/tuya-zigbee-module-uart-communication-protocol?id=K9ear5khsqoty self.log.logging( "Tuya", "Debug", "tuyaReadRawAPS - %s/%s fcf: %s sqn: %s cmd: %s Payload: %s" % ( @@ -288,6 +505,12 @@ def tuyaReadRawAPS(self, Devices, NwkId, srcEp, ClusterID, dstNWKID, dstEP, MsgP _ModelName, NwkId, srcEp, fcf, sqn, cmd, MsgPayload[6:]), NwkId, ) +def tuya_default_response(self, SrcNwkId, SrcEndPoint, ClusterID, Command, Sqn, fcf): + self.log.logging( "Tuya", "Debug", "tuya_default_response - %s/%s %s %s %s %s" %( + SrcNwkId, SrcEndPoint, ClusterID, Command, Sqn, fcf )) + zcl_raw_default_response( self, SrcNwkId, ZIGATE_EP, SrcEndPoint, ClusterID, Command, Sqn, command_status="00", manufcode=None, orig_fcf=fcf ) + + def tuya_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): self.log.logging( "Tuya", "Debug", "tuya_response - Model: %s Nwkid: %s/%s dp: %02x dt: %02x data: %s" % ( @@ -385,7 +608,6 @@ def send_timesynchronisation(self, NwkId, srcEp, ClusterID, dstNWKID, dstEP, ser self.log.logging("Tuya", "Debug", f"send_timesynchronisation - {NwkId}/{srcEp}") - def utc_to_local(dt): # https://stackoverflow.com/questions/4563272/convert-a-python-utc-datetime-to-a-local-datetime-using-only-python-standard-lib if time.localtime().tm_isdst: @@ -394,7 +616,7 @@ def utc_to_local(dt): return dt - timedelta(seconds=time.timezone) -def tuya_send_default_response(self, Nwkid, srcEp, sqn, cmd, orig_fcf): +def tuya_send_default_response(self, Nwkid, srcEp, sqn, cmd, orig_fcf, force_disabled_default=False): if Nwkid not in self.ListOfDevices: return @@ -407,6 +629,9 @@ def tuya_send_default_response(self, Nwkid, srcEp, sqn, cmd, orig_fcf): if disabled_default == "01": return + if force_disabled_default: + disabled_default = "01" + fcf = build_fcf("00", manuf_spec, direction, disabled_default) payload = fcf + sqn + "0b" @@ -727,16 +952,7 @@ def tuya_curtain_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, ds store_tuya_attribute(self, NwkId, "PercentControl", data) elif dp in (0x03, 0x07): - # Curtain Percentage - # We need to translate percentage into Analog value between 0 - 255 - level = ((int(data, 16)) * 255) // 100 - slevel = "%02x" % level - self.log.logging( - "Tuya", - "Debug", - "tuya_curtain_response - Curtain Percentage Nwkid: %s/%s Level %s -> %s" % (NwkId, srcEp, data, level), - NwkId, - ) + slevel = _tuya_percentage_2_analog( data ) store_tuya_attribute(self, NwkId, "PercentState", data) MajDomoDevice(self, Devices, NwkId, srcEp, "0008", slevel) @@ -750,14 +966,7 @@ def tuya_curtain_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, ds store_tuya_attribute(self, NwkId, "DirectionState", data) elif dp in (0x67, 0x69): - level = ((int(data, 16)) * 255) // 100 - slevel = "%02x" % level - self.log.logging( - "Tuya", - "Debug", - "tuya_curtain_response - ?????? Nwkid: %s/%s data %s --> %s" % (NwkId, srcEp, data, level), - NwkId, - ) + slevel = _tuya_percentage_2_analog( data ) MajDomoDevice(self, Devices, NwkId, srcEp, "0008", slevel) store_tuya_attribute(self, NwkId, "dp_%s" % dp, data) @@ -766,6 +975,14 @@ def tuya_curtain_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, ds store_tuya_attribute(self, NwkId, attribute_name, data) +# TODO Rename this here and in `tuya_curtain_response` +def _tuya_percentage_2_analog(data): + # Curtain Percentage + # We need to translate percentage into Analog value between 0 - 255 + level = ((int(data, 16)) * 255) // 100 + return "%02x" % level + + def tuya_curtain_openclose(self, NwkId, openclose): self.log.logging("Tuya", "Debug", "tuya_curtain_openclose - %s OpenClose: %s" % (NwkId, openclose), NwkId) # determine which Endpoint @@ -861,19 +1078,20 @@ def tuya_window_cover_calibration(self, nwkid, duration): write_attribute(self, nwkid, ZIGATE_EP, "01", "0102", "0000", "00", "f003", "21", "%04x" %duration, ackIsDisabled=False) - def tuya_window_cover_motor_reversal(self, nwkid, mode): # (0x0102) | Write Attributes (0x02) | 0xf002 | 8-Bit (0x30) | 0 (0x00) | Off / Default # (0x0102) | Write Attributes (0x02) | 0xf002 | 8-Bit (0x30) | 1 (0x01) | On if int(mode) in {0, 1}: write_attribute( self, nwkid, ZIGATE_EP, "01", "0102", "0000", "00", "f002", "30", "%02x" % int(mode), ackIsDisabled=False ) + def tuya_curtain_mode(self, nwkid, mode): # (0x0006) | Write Attributes (0x02) | 0x8001 | 8-Bit (0x30) | 0 (0x00) | Kick Back # (0x0006) | Write Attributes (0x02) | 0x8001 | 8-Bit (0x30) | 1 (0x01) | Seesaw if int(mode) in {0, 1}: write_attribute( self, nwkid, ZIGATE_EP, "01", "0006", "0000", "00", "8001", "30", "%02x" % int(mode), ackIsDisabled=False ) + def tuya_backlight_command(self, nwkid, mode): if int(mode) in {0, 1, 2}: backlist_attribute = ( "5000" if 'Model' in self.ListOfDevices[nwkid] and self.ListOfDevices[nwkid]["Model"] in ("TS130F-_TZ3000_fvhunhxb", "TS130F-_TZ3000_1dd0d5yi",) else "8001" ) @@ -1092,6 +1310,7 @@ def tuya_smart_motion_all_in_one(self, Devices, _ModelName, NwkId, srcEp, Cluste NwkId, ) + def tuya_pir_keep_time_lookup( self, nwkid, keeptime): keeptime = min( keeptime // 30, 2) @@ -1099,9 +1318,8 @@ def tuya_pir_keep_time_lookup( self, nwkid, keeptime): EPout = "01" write_attribute(self, nwkid, ZIGATE_EP, EPout, "0500", "0000", "00", "f001", "20", "%02x" %keeptime, ackIsDisabled=False) - - + def tuya_garage_door_response( self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): if dp == 0x01: @@ -1124,7 +1342,7 @@ def tuya_garage_door_response( self, Devices, _ModelName, NwkId, srcEp, ClusterI else: store_tuya_attribute(self, NwkId, "dp:%s-dt:%s" %(dp, datatype), data) - + def tuya_garage_door_action( self, NwkId, onoff): # 000f/0101/0001/00 @@ -1138,7 +1356,8 @@ def tuya_garage_door_action( self, NwkId, onoff): data = "%02x" %int(onoff) self.log.logging("Tuya", "Debug", "tuya_garage_door_action - action %s data: %s" % (action,data), NwkId) tuya_cmd(self, NwkId, EPout, cluster_frame, sqn, cmd, action, data) - + + def tuya_garage_run_time(self, NwkId, duration): # 0006/0402/0004/0000001e 30 secondes # 0007/0402/0004/0000003c 60 secondes @@ -1176,6 +1395,7 @@ def tuya_garage_timeout(self, NwkId, duration): 2: 0x02 } + def tuya_external_switch_mode( self, NwkId, mode): self.log.logging("tuyaSettings", "Debug", "tuya_external_switch_mode - mode %s" % mode, NwkId) @@ -1189,19 +1409,22 @@ def tuya_external_switch_mode( self, NwkId, mode): else: write_attribute(self, NwkId, ZIGATE_EP, EPout, TUYA_CLUSTER_EOO1_ID, TUYA_TS0004_MANUF_CODE, "01", "d030", "30", mode, ackIsDisabled=False) + def tuya_TS0004_back_light(self, nwkid, mode): if int(mode) in {0, 1}: write_attribute(self, nwkid, ZIGATE_EP, "01", "0006", "0000", "00", "5000", "30", "%02x" %int(mode), ackIsDisabled=False) else: return - + + def tuya_TS0004_indicate_light(self, nwkid, mode): if int(mode) in {0, 1, 2}: write_attribute(self, nwkid, ZIGATE_EP, "01", "0006", "0000", "00", "8001", "30", "%02x" %int(mode), ackIsDisabled=False) else: return + def SmartRelayStatus_by_ep( self, nwkid, ep, mode): if int(mode) in {0, 1, 2}: @@ -1217,19 +1440,23 @@ def SmartRelayStatus_by_ep( self, nwkid, ep, mode): write_attribute(self, nwkid, ZIGATE_EP, ep, "e001", "0000", "00", "d010", "30", "%02x" %int(mode), ackIsDisabled=False) - + def SmartRelayStatus01(self, nwkid, mode): SmartRelayStatus_by_ep( self, nwkid, "01", mode) - + + def SmartRelayStatus02(self, nwkid, mode): SmartRelayStatus_by_ep( self, nwkid, "02", mode) + def SmartRelayStatus03(self, nwkid, mode): SmartRelayStatus_by_ep( self, nwkid, "03", mode) + def SmartRelayStatus04(self, nwkid, mode): SmartRelayStatus_by_ep( self, nwkid, "04", mode) + def _check_tuya_attribute(self, nwkid, ep, cluster, attribute ): if ep not in self.ListOfDevices[nwkid]["Ep"]: self.log.logging("Heartbeat", "Log", "No ep: %s" %ep, nwkid) @@ -1242,18 +1469,19 @@ def _check_tuya_attribute(self, nwkid, ep, cluster, attribute ): return False return True + def tuya_smoke_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): - self.log.logging("Tuya", "Log", "tuya_smoke_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_smoke_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) if dp == 0x01: # State - self.log.logging("Tuya", "Log", "tuya_smoke_response - Smoke state %s %s %s" % (NwkId, srcEp, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_smoke_response - Smoke state %s %s %s" % (NwkId, srcEp, data), NwkId) store_tuya_attribute(self, NwkId, "SmokeState", data) MajDomoDevice(self, Devices, NwkId, srcEp, "0500", data) elif dp == 0x0e: # 0: Low battery, 2:Full battery , 1: medium ???? - self.log.logging("Tuya", "Log", "tuya_smoke_response - Battery Level %s %s %s" % (NwkId, srcEp, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_smoke_response - Battery Level %s %s %s" % (NwkId, srcEp, data), NwkId) store_tuya_attribute(self, NwkId, "Battery", data) if int(data,16) == 0: self.ListOfDevices[NwkId]["Battery"] = 25 @@ -1267,7 +1495,7 @@ def tuya_smoke_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstN elif dp == 0x04: # Tamper - self.log.logging("Tuya", "Log", "tuya_smoke_response - Tamper %s %s %s" % (NwkId, srcEp, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_smoke_response - Tamper %s %s %s" % (NwkId, srcEp, data), NwkId) store_tuya_attribute(self, NwkId, "SmokeTamper", data) if int(data,16): MajDomoDevice(self, Devices, NwkId, srcEp, "0009", "01") @@ -1275,18 +1503,22 @@ def tuya_smoke_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstN MajDomoDevice(self, Devices, NwkId, srcEp, "0009", "00") else: - self.log.logging("Tuya", "Log", "tuya_smoke_response - Unknow %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_smoke_response - Unknow %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "dp:%s-dt:%s" %(dp, datatype), data) + def tuya_command_f0( self, NwkId ): self.log.logging("Tuya", "Log", "Tuya 0xf0 command to %s" %NwkId) sqn = get_and_inc_ZCL_SQN(self, NwkId) payload = "11" + sqn + "f0" raw_APS_request(self, NwkId, "01", "0000", "0104", payload, zigate_ep=ZIGATE_EP, ackIsDisabled=False) - + + def tuya_temphumi_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): - self.log.logging("Tuya", "Log", "tuya_temphumi_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_temphumi_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + manufacturer_name = self.ListOfDevices[NwkId].get('Manufacturer Name') + if dp == 0x01: # Temperature, unsigned_value = int( data,16) signed_value = struct.unpack('>i', struct.pack('>I', unsigned_value))[0] @@ -1294,37 +1526,54 @@ def tuya_temphumi_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, d store_tuya_attribute(self, NwkId, "Temp", signed_value) MajDomoDevice(self, Devices, NwkId, srcEp, "0402", (signed_value / 10)) checkAndStoreAttributeValue(self, NwkId, "01", "0402", "0000", (signed_value/ 10)) - + elif dp == 0x02: # Humi humi = int(data, 16) - if ( - 'Manufacturer Name' in self.ListOfDevices[ NwkId ] - and self.ListOfDevices[ NwkId ][ 'Manufacturer Name' ] not in ( '_TZE200_qoy0ekbd', '_TZE200_whkgqxse') - ): + if manufacturer_name and manufacturer_name not in {'_TZE200_qoy0ekbd', '_TZE200_whkgqxse', '_TZE204_upagmta9'}: humi /= 10 store_tuya_attribute(self, NwkId, "Humi", humi) MajDomoDevice(self, Devices, NwkId, srcEp, "0405", humi) checkAndStoreAttributeValue(self, NwkId, "01", "0405", "0000", humi) - + elif dp == 0x04: # Battery ???? store_tuya_attribute(self, NwkId, "Battery", data) checkAndStoreAttributeValue(self, NwkId, "01", "0001", "0000", int(data, 16)) self.ListOfDevices[NwkId]["Battery"] = int(data, 16) Update_Battery_Device(self, Devices, NwkId, int(data, 16)) store_tuya_attribute(self, NwkId, "BatteryStatus", data) + + elif dp == 0x03: + # 0: Low battery, 2:Full battery , 1: medium ???? + self.log.logging("Tuya", "Debug", "tuya_temphumi_response - Battery Level %s %s %s" % (NwkId, srcEp, data), NwkId) + store_tuya_attribute(self, NwkId, "Battery", data) + if int(data,16) == 0: + self.ListOfDevices[NwkId]["Battery"] = 25 + Update_Battery_Device(self, Devices, NwkId, 25) + elif int(data,16) == 1: + self.ListOfDevices[NwkId]["Battery"] = 50 + Update_Battery_Device(self, Devices, NwkId, 50) + else: + self.ListOfDevices[NwkId]["Battery"] = 90 + Update_Battery_Device(self, Devices, NwkId, 90) + + elif dp == 0x09: + # Temp Unit + self.log.logging("Tuya", "Debug", "tuya_temphumi_response - Temp Unit %s %s %s" % (NwkId, srcEp, data), NwkId) + store_tuya_attribute(self, NwkId, "TempUnit", data) + else: self.log.logging("Tuya", "Log", "tuya_temphumi_response - Unknow %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "dp:%s-dt:%s" %(dp, datatype), data) - + def tuya_motion_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): - self.log.logging("Tuya", "Log", "tuya_motion_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) if dp == 0x01: # Occupancy - self.log.logging("Tuya", "Log", "tuya_motion_response - Occupancy %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - Occupancy %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) # Looks like the Occupancy indicator is inverse occupancy = "%02x" %abs(int(data,16) -1 ) store_tuya_attribute(self, NwkId, "Occupancy", data) @@ -1333,7 +1582,7 @@ def tuya_motion_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dst elif dp == 0x04: # Battery - self.log.logging("Tuya", "Log", "tuya_motion_response - Battery %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - Battery %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "Battery", data) checkAndStoreAttributeValue(self, NwkId, "01", "0001", "0000", int(data, 16)) @@ -1343,19 +1592,19 @@ def tuya_motion_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dst elif dp == 0x09: # Sensitivity - {'0': 'low', '1': 'medium', '2': 'high'} - self.log.logging("Tuya", "Log", "tuya_motion_response - Sensitivity %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - Sensitivity %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "Sensitivity", data) elif dp == 0x0a: # Keep time - {'0': '10', '1': '30', '2': '60', '3': '120'} - self.log.logging("Tuya", "Log", "tuya_motion_response - Keep Time %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - Keep Time %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "KeepTime", data) elif dp == 0x0c: # Illuminance - self.log.logging("Tuya", "Log", "tuya_motion_response - Illuminance %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) + self.log.logging("Tuya", "Debug", "tuya_motion_response - Illuminance %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "Illuminance", data) MajDomoDevice(self, Devices, NwkId, srcEp, "0400", (int(data, 16)) ) @@ -1365,6 +1614,7 @@ def tuya_motion_response(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dst self.log.logging("Tuya", "Log", "tuya_motion_response - Unknow %s %s %s %s %s" % (NwkId, srcEp, dp, datatype, data), NwkId) store_tuya_attribute(self, NwkId, "dp:%s-dt:%s" %(dp, datatype), data) + def tuya_motion_zg204l_sensitivity(self, nwkid, sensitivity): # {'low': 0, 'medium': 1, 'high': 2} self.log.logging("tuyaSettings", "Debug", "tuya_motion_zg204l_keeptime - %s mode: %s" % (nwkid, sensitivity)) @@ -1482,8 +1732,6 @@ def tuya_radar_motion_radar_fading_time(self, nwkid, mode): tuya_cmd(self, nwkid, EPout, cluster_frame, sqn, cmd, action, data) - - def tuya_smart_door_lock(self, Devices, _ModelName, NwkId, srcEp, ClusterID, dstNWKID, dstEP, dp, datatype, data): store_tuya_attribute(self, NwkId, "dp:%s-dt:%s" %(dp, datatype), data) @@ -1521,18 +1769,22 @@ def ts110e_light_type( self, NwkId, mode): mode = "%02x" %mode write_attribute(self, NwkId, ZIGATE_EP, EPout, "0008", "0000", "00", "fc02", "20", mode, ackIsDisabled=False) + def ts110e_switch01_type( self, NwkId, mode): ts110e_switch_type( self, NwkId, "01", mode) + def ts110e_switch02_type( self, NwkId, mode): ts110e_switch_type( self, NwkId, "02", mode) + def ts110e_switch_type( self, NwkId, EPout, mode): # momentary: 0, toggle: 1, state: 2 self.log.logging("tuyaSettings", "Debug", "ts110e_switch_type - mode %s" % mode, NwkId) mode = "%02x" %mode write_attribute(self, NwkId, ZIGATE_EP, EPout, "0008", "0000", "00", "fc02", "20", mode, ackIsDisabled=False) + def tuya_lighting_color_control( self, NwkId, ColorCapabilities=25): # The ColorCapabilities attribute specifies the color capabilities of the device supporting the color control clus- # ter, as illustrated in Table 5.8. If a bit is set to 1, the corresponding attributes and commands SHALL become @@ -1557,6 +1809,7 @@ def tuya_color_control_rgbMode( self, NwkId, mode): payload = "11" + sqn + "f0" + mode raw_APS_request(self, NwkId, "01", "0300", "0104", payload, zigpyzqn=sqn, zigate_ep=ZIGATE_EP, ackIsDisabled=False) + def tuya_Move_To_Hue_Saturation( self, NwkId, EPout, hue, saturation, transition, level): # Command 0x06 self.log.logging("Tuya", "Debug", "tuya_Move_To_Hue_Saturation", NwkId) diff --git a/Modules/tuyaTRV.py b/Modules/tuyaTRV.py index e76f21822..46e6f006a 100644 --- a/Modules/tuyaTRV.py +++ b/Modules/tuyaTRV.py @@ -32,7 +32,7 @@ from Modules.zigateConsts import ZIGATE_EP -def tuya_eTRV_registration(self, nwkid, device_reset=False): +def tuya_eTRV_registration(self, nwkid, tuya_data_request=False): self.log.logging("Tuya", "Debug", "tuya_eTRV_registration - Nwkid: %s" % nwkid) # (1) 3 x Write Attribute Cluster 0x0000 - Attribute 0xffde - DT 0x20 - Value: 0x13 @@ -40,7 +40,7 @@ def tuya_eTRV_registration(self, nwkid, device_reset=False): write_attribute(self, nwkid, ZIGATE_EP, EPout, "0000", "0000", "00", "ffde", "20", "13", ackIsDisabled=False) # (3) Cmd 0x03 on Cluster 0xef00 (Cluster Specific) - if device_reset and get_model_name(self, nwkid) not in ("TS0601-thermostat", "TS0601-thermostat-Coil", "TS0601-eTRV5", ): + if tuya_data_request and get_model_name(self, nwkid) not in ("TS0601-thermostat", "TS0601-thermostat-Coil", "TS0601-eTRV5", ): payload = "11" + get_and_inc_ZCL_SQN(self, nwkid) + "03" raw_APS_request( self, diff --git a/Modules/tuyaTS0601.py b/Modules/tuyaTS0601.py index 8d4b562cd..99f717f8e 100644 --- a/Modules/tuyaTS0601.py +++ b/Modules/tuyaTS0601.py @@ -22,6 +22,7 @@ from Modules.domoMaj import MajDomoDevice from Modules.domoTools import Update_Battery_Device from Modules.tools import (checkAndStoreAttributeValue, get_and_inc_ZCL_SQN, + get_device_config_param, get_deviceconf_parameter_value, getAttributeValue) from Modules.tuyaTools import (get_tuya_attribute, store_tuya_attribute, tuya_cmd) @@ -60,6 +61,7 @@ def ts0601_response(self, Devices, model_name, NwkId, Ep, dp, datatype, data): process_dp_item( self, Devices, model_name, NwkId, Ep, dp, datatype, data, dps_mapping_item, value) return True + def process_dp_item( self, Devices, model_name, NwkId, Ep, dp, datatype, data, dps_mapping_item, value): if "EvalExp" in dps_mapping_item: value = evaluate_expression_with_data(self, dps_mapping_item[ "EvalExp"], value) @@ -166,8 +168,8 @@ def ts0601_actuator( self, NwkId, command, value=None): else: func(self, NwkId, "01", dp ) -# Helpers +# Helpers def process_sensor_data(self, sensor_type, dps_mapping_item, value, Devices, NwkId, domo_ep): if sensor_type in DP_SENSOR_FUNCTION: formatted_value = check_domo_format_req(self, dps_mapping_item, value) @@ -176,16 +178,18 @@ def process_sensor_data(self, sensor_type, dps_mapping_item, value, Devices, Nwk return True return False - + def read_uint16_be(data, offset): # Use the format '>H' to specify big-endian (>) and 'H' for 16-bit unsigned integer. return struct.unpack_from('>H', data, offset)[0] + def read_uint8(data, offset): # Use indexing to get the byte at the specified offset # and convert it to an unsigned integer using ord(). return ord(data[offset]) + def evaluate_expression_with_data(self, expression, value): try: return eval( expression ) @@ -204,6 +208,7 @@ def evaluate_expression_with_data(self, expression, value): return value + def check_domo_format_req( self, dp_informations, value): if "DomoDeviceFormat" not in dp_informations: @@ -215,6 +220,7 @@ def check_domo_format_req( self, dp_informations, value): return value + def ts0601_extract_data_point_infos( self, model_name): if model_name not in self.DeviceConf: @@ -228,7 +234,6 @@ def ts0601_actuator_dp( command, dps_mapping): # Sensors responses - def ts0601_motion(self, Devices, nwkid, ep, value): # Occupancy self.log.logging("Tuya0601", "Debug", "ts0601_motion - Occupancy %s %s %s" % (nwkid, ep, value), nwkid) @@ -236,12 +241,14 @@ def ts0601_motion(self, Devices, nwkid, ep, value): MajDomoDevice(self, Devices, nwkid, ep, "0406", value ) checkAndStoreAttributeValue(self, nwkid, "01", "0406", "0000", value) + def ts0601_tuya_presence_state(self, Devices, nwkid, ep, value): # Presence State ( None, Present, Moving ) self.log.logging("Tuya0601", "Debug", "ts0601_tuya_presence_state - state %s %s %s" % (nwkid, ep, value), nwkid) store_tuya_attribute(self, nwkid, "presence_state", value) MajDomoDevice(self, Devices, nwkid, ep, "0006", value ) + def ts0601_illuminance(self, Devices, nwkid, ep, value): # Illuminance self.log.logging("Tuya0601", "Debug", "ts0601_illuminance - Illuminance %s %s %s" % (nwkid, ep, value), nwkid) @@ -250,13 +257,22 @@ def ts0601_illuminance(self, Devices, nwkid, ep, value): checkAndStoreAttributeValue(self, nwkid, "01", "0400", "0000", value) -def ts0601_temperature(self, Devices, nwkid, ep, value): +def ts0601_illuminance_20min_averrage(self, Devices, nwkid, ep, value): + # Illuminance + self.log.logging("Tuya0601", "Debug", "ts0601_illuminance - Illuminance %s %s %s" % (nwkid, ep, value), nwkid) + store_tuya_attribute(self, nwkid, "Illuminance_20min_Average", value) + MajDomoDevice(self, Devices, nwkid, ep, "0400", value, Attribute_="ff00") + checkAndStoreAttributeValue(self, nwkid, "01", "0400", "0000", value) + +def ts0601_temperature(self, Devices, nwkid, ep, value): store_tuya_attribute(self, nwkid, "Temp", value) checkAndStoreAttributeValue(self, nwkid, "01", "0402", "0000", value) + compensation = get_device_config_param( self, nwkid, "tempCompensation") or 0 + value += compensation MajDomoDevice(self, Devices, nwkid, ep, "0402", value) - + def ts0601_humidity(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_humidity - humidity %s %s %s " % (nwkid, ep, value), nwkid) store_tuya_attribute(self, nwkid, "Humi", value) @@ -271,13 +287,14 @@ def ts0601_distance(self, Devices, nwkid, ep, value): def ts0601_battery(self, Devices, nwkid, ep, value ): self.log.logging("Tuya0601", "Debug", "ts0601_battery - Battery %s %s %s" % (nwkid, ep, value), nwkid) - store_tuya_attribute(self, nwkid, "Battery", value) checkAndStoreAttributeValue(self, nwkid, "01", "0001", "0000", value) self.ListOfDevices[nwkid]["Battery"] = value Update_Battery_Device(self, Devices, nwkid, value) + MajDomoDevice(self, Devices, nwkid, ep, "0001", value, Attribute_="0021",) store_tuya_attribute(self, nwkid, "BatteryStatus", value) + def ts0601_battery_state(self, Devices, nwkid, ep, value ): self.log.logging("Tuya0601", "Debug", "ts0601_battery_state - Battery %s %s %s" % (nwkid, ep, value), nwkid) store_tuya_attribute(self, nwkid, "BatteryState", value) @@ -288,7 +305,8 @@ def ts0601_tamper(self, Devices, nwkid, ep, value): store_tuya_attribute(self, nwkid, "Tamper", value) state = "01" if value != 0 else "00" MajDomoDevice(self, Devices, nwkid, ep, "0009", state) - + + def ts0601_charging_mode(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_charging_mode - Charging %s %s %s" % (nwkid, ep, value), nwkid) store_tuya_attribute(self, nwkid, "Tamper", value) @@ -297,7 +315,8 @@ def ts0601_charging_mode(self, Devices, nwkid, ep, value): MajDomoDevice(self, Devices, nwkid, ep, "Notification", "Charging On") else: MajDomoDevice(self, Devices, nwkid, ep, "Notification", "Charging Off") - + + def ts0601_switch(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_switch - Switch%s %s %s" % (nwkid, ep, value), nwkid) store_tuya_attribute(self, nwkid, "Switch", value) @@ -307,7 +326,7 @@ def ts0601_switch(self, Devices, nwkid, ep, value): def ts0601_level_percentage(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_level_percentage - Percentage%s %s %s" % (nwkid, ep, value), nwkid, ) - store_tuya_attribute(self, nwkid, "PercentState", value) + store_tuya_attribute(self, nwkid, "PercentLevel", value) MajDomoDevice(self, Devices, nwkid, ep, "0008", "%02x" %value) @@ -348,11 +367,13 @@ def ts0601_current(self, Devices, nwkid, ep, value): checkAndStoreAttributeValue(self, nwkid, ep, "0b04", "0508", value) # Store int store_tuya_attribute(self, nwkid, "Current_%s" %ep, value) + def ts0601_power_factor(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_power_factor - Power Factor %s %s %s" % (nwkid, ep, value), nwkid, ) MajDomoDevice(self, Devices, nwkid, ep, "PWFactor", value) store_tuya_attribute(self, nwkid, "PowerFactor_%s" %ep, value) + def ts0601_summation_energy(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_summation_energy - Current Summation %s %s %s" % (nwkid, ep, value), nwkid, ) previous_summation = getAttributeValue(self, nwkid, ep, "0702", "0000") @@ -363,48 +384,57 @@ def ts0601_summation_energy(self, Devices, nwkid, ep, value): checkAndStoreAttributeValue(self, nwkid, ep, "0702", "0000", current_summation) # Store int store_tuya_attribute(self, nwkid, "Energy_%s" %ep, value) + def ts0601_summation_energy_raw(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_summation_energy - Current Summation %s %s %s" % (nwkid, ep, value), nwkid, ) MajDomoDevice(self, Devices, nwkid, ep, "0702", value, Attribute_="0000") checkAndStoreAttributeValue(self, nwkid, ep, "0702", "0000", value) # Store int store_tuya_attribute(self, nwkid, "ConsumedEnergy_%s" %ep, value) + def ts0601_production_energy(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_production_energy - Production Energy %s %s %s" % (nwkid, ep, value), nwkid, ) MajDomoDevice(self, Devices, nwkid, ep, "0702", value, Attribute_="0001") checkAndStoreAttributeValue(self, nwkid, ep, "0702", "0001", value) # Store int store_tuya_attribute(self, nwkid, "ProducedEnergy_%s" %ep, value) + def ts0601_instant_power(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_instant_power - Instant Power %s %s %s" % (nwkid, ep, value), nwkid, ) # Given Zigbee 24-bit integer and tuya store in two's complement form model_name = self.ListOfDevices[ nwkid ]["Model"] if "Model" in self.ListOfDevices[ nwkid ] else None + + signed_int = value + rely_on_eval_expression = get_deviceconf_parameter_value( self, model_name, "RELY_ON_EVAL_EXP", return_default=False ) - twocomplement_tst = int( get_deviceconf_parameter_value( self, model_name, "TWO_COMPLEMENT_TST", return_default="0" ),16) - twocomplement_val = int( get_deviceconf_parameter_value( self, model_name, "TWO_COMPLEMENT_VAL", return_default="0" ),16) - self.log.logging( "Tuya0601", "Debug", "ts0601_instant_power - Instant Power Two's Complement : %s %s" %( - twocomplement_tst, twocomplement_val)) self.log.logging( "Tuya0601", "Debug", "ts0601_instant_power - Rely on Eval Exp : %s" %( rely_on_eval_expression)) - signed_int = value + if not rely_on_eval_expression: signed_int = int( value ) + + twocomplement_tst = int( get_deviceconf_parameter_value( self, model_name, "TWO_COMPLEMENT_TST", return_default="0" ),16) + twocomplement_val = int( get_deviceconf_parameter_value( self, model_name, "TWO_COMPLEMENT_VAL", return_default="0" ),16) + if twocomplement_tst: signed_int = signed_int - twocomplement_val if signed_int & twocomplement_tst else signed_int + elif (signed_int & 0x00800000) != 0: # Check the sign bit signed_int -= 0x01000000 # If negative, adjust to two's complement - self.log.logging( "Tuya0601", "Debug", "ts0601_instant_power - Instant Power Two's Complement : value: %s" %signed_int) + self.log.logging( "Tuya0601", "Debug", "ts0601_instant_power - Instant Power Two's Complement result signed_int: %s" %signed_int) checkAndStoreAttributeValue(self, nwkid, ep, "0702", "0400", signed_int) MajDomoDevice(self, Devices, nwkid, ep, "0702", signed_int) store_tuya_attribute(self, nwkid, "InstantPower_%s" %ep, signed_int) # Store str + def ts0601_voltage(self, Devices, nwkid, ep, value): self.log.logging( "Tuya0601", "Debug", "ts0601_voltage - Voltage %s %s %s" % (nwkid, ep, value), nwkid, ) MajDomoDevice(self, Devices, nwkid, ep, "0001", value) store_tuya_attribute(self, nwkid, "Voltage_%s" %ep, value) + def ts0601_trv7_system_mode(self, Devices, nwkid, ep, value): # Auto 0, Manual 1, Off 2 # Widget 0: Off, 1: Auto, 2: Manual @@ -426,7 +456,38 @@ def ts0601_trv7_system_mode(self, Devices, nwkid, ep, value): widget_value = DEVICE_WIDGET_MAP[ value ] MajDomoDevice(self, Devices, nwkid, ep, "0201", widget_value, Attribute_="001c") checkAndStoreAttributeValue(self, nwkid, "01", "0201", "0012", widget_value) - + +WIDGET_BAB_1413Pro_E_RESPONSE = { + # "LevelNames": "Off|Manual|Auto|Eco|Confort|Holidays", + 0x00: 2, + 0x01: 5, + 0x02: 1, + 0x03: 4, + 0x04: 3 + } + +def ts0601_trv8_system_mode(self, Devices, nwkid, ep, value): + # Manual: 0x02 + # Programming: 0x00 + # Eco: 0x04 + # Confort: 0x03 + # Holiday: 0x01 + + if value > 4: + self.log.logging("Tuya0601", "Error", "ts0601_trv8_system_mode - After Nwkid: %s/%s Invalid SystemMode: %s" % (nwkid, ep, value)) + return + + self.log.logging("Tuya0601", "Debug", "ts0601_trv8_system_mode - After Nwkid: %s/%s SystemMode: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "SystemModel", value) + if value not in WIDGET_BAB_1413Pro_E_RESPONSE: + self.log.logging("Tuya0601", "Error", "ts0601_trv8_system_mode - unexepected mode %s/%s mode: %s (%s)" %( + nwkid, ep, value, type(value)) + ) + widget_value = WIDGET_BAB_1413Pro_E_RESPONSE[ value ] + MajDomoDevice(self, Devices, nwkid, ep, "0201", widget_value, Attribute_="001c") + checkAndStoreAttributeValue(self, nwkid, "01", "0201", "0012", widget_value) + + def ts0601_trv6_system_mode(self, Devices, nwkid, ep, value): # Auto 0, Manual 1, Off 2 # Widget 0: Off, 1: Auto, 2: Manual @@ -441,16 +502,19 @@ def ts0601_trv6_system_mode(self, Devices, nwkid, ep, value): MajDomoDevice(self, Devices, nwkid, ep, "0201", value, Attribute_="001c") checkAndStoreAttributeValue(self, nwkid, "01", "0201", "0012", value) + def ts0601_sirene_switch(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_sirene_switch - After Nwkid: %s/%s Alarm: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "Alarm", value) MajDomoDevice(self, Devices, nwkid, ep, "0006", value) - + + def ts0601_tamper_switch(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_sirene_switch - After Nwkid: %s/%s Alarm: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "Alarm", value) MajDomoDevice(self, Devices, nwkid, ep, "0006", value) - + + def ts0601_sirene_level(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_sirene_level - Sound Level: %s" % value, nwkid) store_tuya_attribute(self, nwkid, "AlarmLevel", value) @@ -459,7 +523,8 @@ def ts0601_sirene_level(self, Devices, nwkid, ep, value): def ts0601_sirene_duration(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_sirene_duration - After Nwkid: %s/%s Alarm: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "AlarmDuration", value) - + + def ts0601_sirene_melody(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_sirene_melody - After Nwkid: %s/%s Alarm: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "AlarmMelody", value) @@ -508,35 +573,68 @@ def ts0601_smoke_concentration(self, Devices, nwkid, ep, value): def ts0601_phMeter(self, Devices, nwkid, ep, value): - self.log.logging("Tuya0601", "Debug", "ts0601_phMeter - Nwkid: %s/%s Smoke Concentration: %s" % (nwkid, ep, value)) - store_tuya_attribute(self, nwkid, "phMeter", value) + self.log.logging("Tuya0601", "Debug", "ts0601_phMeter - Nwkid: %s/%s ph meter: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "PH", value) + compensation = get_device_config_param( self, nwkid, "ph7Compensation") or 0 + value += compensation MajDomoDevice(self, Devices, nwkid, ep, "phMeter", value) def ts0601_ec(self, Devices, nwkid, ep, value): - self.log.logging("Tuya0601", "Debug", "ts0601_ec - Nwkid: %s/%s Smoke Concentration: %s" % (nwkid, ep, value)) + self.log.logging("Tuya0601", "Debug", "ts0601_ec - Nwkid: %s/%s EC: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "Electric Conductivity", value) + compensation = get_device_config_param( self, nwkid, "ecCompensation") or 0 + value += compensation MajDomoDevice(self, Devices, nwkid, ep, "ec", value) def ts0601_orp(self, Devices, nwkid, ep, value): - self.log.logging("Tuya0601", "Debug", "ts0601_orp - Nwkid: %s/%s Smoke Concentration: %s" % (nwkid, ep, value)) - store_tuya_attribute(self, nwkid, "Oxidation Reduction Potential", value) + self.log.logging("Tuya0601", "Debug", "ts0601_orp - Nwkid: %s/%s ORP: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "Oxydation Reduction Potential", value) + compensation = get_device_config_param( self, nwkid, "orpCompensation") or 0 + value += compensation + MajDomoDevice(self, Devices, nwkid, ep, "orp", value) def ts0601_freeChlorine(self, Devices, nwkid, ep, value): - self.log.logging("Tuya0601", "Debug", "ts0601_freeChlorine - Nwkid: %s/%s Smoke Concentration: %s" % (nwkid, ep, value)) + self.log.logging("Tuya0601", "Debug", "ts0601_freeChlorine - Nwkid: %s/%s Free Chlorine: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "Free chlorine", value) MajDomoDevice(self, Devices, nwkid, ep, "freeChlorine", value) -def ts0601_salinity(self, Devices, nwkid, ep, value): - self.log.logging("Tuya0601", "Debug", "ts0601_salinity - Nwkid: %s/%s Smoke Concentration: %s" % (nwkid, ep, value)) - store_tuya_attribute(self, nwkid, "Salt", value) +def ts0601_salinity(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_salinity - Nwkid: %s/%s Salinity: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "Salinity", value) MajDomoDevice(self, Devices, nwkid, ep, "salinity", value) +def ts0601_tds(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_tds - Nwkid: %s/%s Total Dissolved Solids: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "Total Dissolved Solids", value) + MajDomoDevice(self, Devices, nwkid, ep, "tds", value) + + +def ts0601_phCalibration1(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_phCalibration1 - Nwkid: %s/%s phCalibration1: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "ph Calibration1", value) + + +def ts0601_phCalibration2(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_phCalibration2 - Nwkid: %s/%s phCalibration2: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "ph Calibration2", value) + + +def ts0601_ecCalibration(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_ecCalibration - Nwkid: %s/%s ecCalibration: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "ec Calibration", value) + + +def ts0601_orpCalibration(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_orpCalibration - Nwkid: %s/%s orpCalibration: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "orp Calibration", value) + + def ts0601_water_consumption(self, Devices, nwkid, ep, value): self.log.logging("Tuya0601", "Debug", "ts0601_water_consumption - Nwkid: %s/%s WaterConsumtpion: %s" % (nwkid, ep, value)) store_tuya_attribute(self, nwkid, "WaterConsumtpion", value) @@ -555,9 +653,63 @@ def ts0601_sensor_irrigation_mode(self, Devices, nwkid, ep, value): MajDomoDevice(self, Devices, nwkid, ep, "0008", value) +def ts0601_curtain_state(self, Devices, nwkid, ep, value): + # 0x02: Off + # 0x01: Stop + # 0x00: Open + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_state - Nwkid: %s/%s State: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "CurtainState", value) + STATE_TO_BLIND = { + 0x00: "01", # Open + 0x02: "00", # Closed/Off + } + + if value in STATE_TO_BLIND: + MajDomoDevice(self, Devices, nwkid, ep, "0006", STATE_TO_BLIND[ value ]) + + +def ts0601_curtain_level(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_level - Nwkid: %s/%s Level: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "CurtainLevel", value) + + # It is a bit odd, but MajDomoDevice on "0008" expects an analog value between 0 to 255, so we need to convert the % into analog on a scale of 255 + analog_value = (value * 255) // 100 + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_level - Nwkid: %s/%s Level: %s analog: %s" % (nwkid, ep, value, analog_value)) + MajDomoDevice(self, Devices, nwkid, ep, "0008", analog_value) + + +def ts0601_curtain_calibration(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_calibration - Nwkid: %s/%s Mode: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "CurtainCalibrationMode", value) + + +def ts0601_curtain_motor_steering(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_motor_steering - Nwkid: %s/%s Steering: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "CurtainMotorSteering", value) + + +def ts0601_cleaning_reminder(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_cleaning_reminder - Nwkid: %s/%s Level: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "CleaningReminder", value) + self.log.logging("Tuya0601", "Debug", "ts0601_cleaning_reminder - Nwkid: %s/%s Level: %s analog: %s" % (nwkid, ep, value, value)) + MajDomoDevice(self, Devices, nwkid, ep, "0006", value) + + +def ts0601_rain_intensity(self, Devices, nwkid, ep, value): + self.log.logging("Tuya0601", "Debug", "ts0601_rain_intensity - Nwkid: %s/%s Level: %s" % (nwkid, ep, value)) + store_tuya_attribute(self, nwkid, "RainIntensity", value) + self.log.logging("Tuya0601", "Debug", "ts0601_rain_intensity - Nwkid: %s/%s Level: %s analog: %s" % (nwkid, ep, value, value)) + MajDomoDevice(self, Devices, nwkid, ep, "RainIntensity", value) + + DP_SENSOR_FUNCTION = { + "curtain_state": ts0601_curtain_state, + "curtain_level": ts0601_curtain_level, + "curtain_calibration": ts0601_curtain_calibration, + "curtain_motor_steering": ts0601_curtain_motor_steering, "motion": ts0601_motion, "illuminance": ts0601_illuminance, + "illuminance_20min_average": ts0601_illuminance_20min_averrage, "temperature": ts0601_temperature, "setpoint": ts0601_setpoint, "humidity": ts0601_humidity, @@ -585,6 +737,7 @@ def ts0601_sensor_irrigation_mode(self, Devices, nwkid, ep, value): "windowsopened": ts0601_windowdetection, "TRV6SystemMode": ts0601_trv6_system_mode, "TRV7SystemMode": ts0601_trv7_system_mode, + "TRV8SystemMode": ts0601_trv8_system_mode, "TuyaAlarmDuration": ts0601_sirene_duration, "TuyaAlarmMelody": ts0601_sirene_melody, "TuyaAlarmLevel": ts0601_sirene_level, @@ -599,16 +752,24 @@ def ts0601_sensor_irrigation_mode(self, Devices, nwkid, ep, value): "ec": ts0601_ec, "orp": ts0601_orp, "freeChlorine": ts0601_freeChlorine, - "salinity": ts0601_salinity - + "salinity": ts0601_salinity, + "tds": ts0601_tds, + "phCalibration1": ts0601_phCalibration1, + "phCalibration2": ts0601_phCalibration2, + "ecCalibration": ts0601_ecCalibration, + "orpCalibration": ts0601_orpCalibration, + "cleaning_reminder": ts0601_cleaning_reminder, + "rain_intensity": ts0601_rain_intensity, } + def ts0601_tuya_cmd(self, NwkId, Ep, action, data): self.log.logging("Tuya0601", "Debug", "ts0601_tuya_cmd - %s %s %s %s" % (NwkId, Ep, action, data)) cluster_frame = "11" sqn = get_and_inc_ZCL_SQN(self, NwkId) - self.log.logging("Tuya0601", "Debug", "ts0601_tuya_cmd - %s %s sqn: %s" % (NwkId, Ep, sqn)) + + self.log.logging("Tuya0601", "Debug", "ts0601_tuya_cmd - %s %s sqn: %s action: %s data: %s" % (NwkId, Ep, sqn, action, data)) tuya_cmd(self, NwkId, Ep, cluster_frame, sqn, "00", action, data) @@ -656,6 +817,26 @@ def ts0601_action_setpoint(self, NwkId, Ep, dp, value): ts0601_tuya_cmd(self, NwkId, Ep, action, data) +def ts0601_max_setpoint_temp( self, NwkId, Ep, dp, value=None): + if value is None: + return + + self.log.logging("Tuya0601", "Debug", "ts0601_max_setpoint_temp - %s Max SetPoint: %s" % (NwkId, value)) + action = "%02x02" % dp + data = "%08x" % value + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + +def ts0601_min_setpoint_temp( self, NwkId, Ep, dp, value=None): + if value is None: + return + + self.log.logging("Tuya0601", "Debug", "ts0601_min_setpoint_temp - %s Min SetPoint: %s" % (NwkId, value)) + action = "%02x02" % dp + data = "%08x" % value + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + def ts0601_settings( self, NwkId, dps_mapping, param, value): """ Handle in a more generic way TS0601 settings, by extracting Data Type from the config """ @@ -759,6 +940,36 @@ def ts0601_action_trv6_system_mode(self, NwkId, Ep, dp, value=None): data = "%02x" % (device_value) ts0601_tuya_cmd(self, NwkId, Ep, action, data) +WIDGET_BAB_1413Pro_E_COMMAND = { + # "LevelNames": "Off|Manual|Auto|Eco|Confort|Holidays", + 1: 0x02, + 2: 0x00, + 3: 0x04, + 4: 0x03, + 5: 0x01 + } + +def ts0601_action_trv8_system_mode(self, NwkId, Ep, dp, value=None): + # Manual: 0x02 + # Programming: 0x00 + # Eco: 0x04 + # Confort: 0x03 + # Holiday: 0x01 + + if value is None: + return + + self.log.logging("Tuya0601", "Debug", "ts0601_action_trv6bis_system_mode - %s System mode: %s" % (NwkId, value)) + if value not in WIDGET_BAB_1413Pro_E_COMMAND: + self.log.logging("Tuya0601", "Error", "ts0601_action_trv6_system_mode - unexepected mode %s/%s mode: %s (%s)" %( + NwkId, Ep, value, type(value)) + ) + device_value = WIDGET_BAB_1413Pro_E_COMMAND[ value ] + + action = "%02x04" % dp # Mode + data = "%02x" % (device_value) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + def ts0601_action_siren_switch(self, NwkId, Ep, dp, value=None): if value is None: @@ -875,7 +1086,64 @@ def ts0601_solar_siren_alarm_duration( self, NwkId, Ep, dp, duration=None): ts0601_tuya_cmd(self, NwkId, Ep, action, data) +def ts0601_curtain_state_cmd( self, NwkId, Ep, dp, openclose=None): + if openclose is None: + return + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_state_cmd - %s Switch Action: dp:%s value: %s" % ( + NwkId, dp, openclose)) + action = "%02x04" % dp # I + data = "%02x" % (openclose) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + +def ts0601_curtain_level_cmd( self, NwkId, Ep, dp, percent=None): + if percent is None: + return + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_level_cmd - %s Switch Action: dp:%s value: %s" % ( + NwkId, dp, percent)) + action = "%02x02" % dp # I + data = "%08x" % (percent) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + +def ts0601_curtain_calibration_cmd( self, NwkId, Ep, dp, mode=None): + if mode is None: + return + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_calibration_cmd - %ss dp:%s value: %s" % ( + NwkId, dp, mode)) + action = "%02x01" % dp # I + data = "%02x" % (mode) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + +def ts0601_curtain_motor_steering_cmd( self, NwkId, Ep, dp, mode=None): + # mode 0x00: Forward + # mode 0x01: Backward + if mode is None: + return + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_motor_steering_cmd - %s Switch Action: dp:%s value: %s" % ( + NwkId, dp, mode)) + action = "%02x02" % dp # I + data = "%08x" % (mode) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + +def ts0601_curtain_quick_calibration_cmd( self, NwkId, Ep, dp, duration=None): + if duration is None: + return + self.log.logging("Tuya0601", "Debug", "ts0601_curtain_quick_calibration_cmd - %s Quick Calibration: dp:%s value: %s" % ( + NwkId, dp, duration)) + action = "%02x04" % dp # I + data = "%02x" % (duration) + ts0601_tuya_cmd(self, NwkId, Ep, action, data) + + TS0601_COMMANDS = { + "CurtainState": ts0601_curtain_state_cmd, + "CurtainLevel": ts0601_curtain_level_cmd, + "CurtainCalibration": ts0601_curtain_calibration_cmd, + "CurtainQuickCalibration": ts0601_curtain_quick_calibration_cmd, + "CurtainMotorSteering": ts0601_curtain_motor_steering_cmd, "TuyaPresenceSensitivity": ( None, "04"), "TuyaRadarSensitivity": (None, "04"), "TuyaRadarMaxRange": ( None, "02" ), @@ -892,14 +1160,18 @@ def ts0601_solar_siren_alarm_duration( self, NwkId, Ep, dp, duration=None): "TuyaIrrigationMode": ts0601_irrigation_mode, "TuyaAlarmMelody": ts0601_solar_siren_alarm_melody, "TuyaAlarmMode": ts0601_solar_siren_alarm_mode, - "TuyaAlarmDuration": ts0601_solar_siren_alarm_duration + "TuyaAlarmDuration": ts0601_solar_siren_alarm_duration, + "MaxSetpointTemp": ts0601_max_setpoint_temp, + "MinSetpointTemp": ts0601_min_setpoint_temp, } + DP_ACTION_FUNCTION = { "switch": ts0601_action_switch, "setpoint": ts0601_action_setpoint, "calibration": ts0601_action_calibration, "TRV6SystemMode": ts0601_action_trv6_system_mode, + "TRV8SystemMode": ts0601_action_trv8_system_mode, "TRV7SystemMode": ts0601_action_trv7_system_mode, "TuyaAlarmSwitch": ts0601_action_siren_switch, "TuyaTamperSwitch": ts0601_tamper_siren_switch, diff --git a/Modules/tuyaTools.py b/Modules/tuyaTools.py index a7eaf48a2..4af74aee4 100644 --- a/Modules/tuyaTools.py +++ b/Modules/tuyaTools.py @@ -61,11 +61,11 @@ def tuya_read_attribute(self, nwkid, EPout, cluster_frame, sqn, cmd, action, dat zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), ) - self.log.logging("Tuya", "Debug", "tuya_read_attribute - %s/%s cmd: %s payload: %s" % (nwkid, EPout, cmd, payload)) + self.log.logging(["Tuya0601", "Tuya"], "Debug", "tuya_read_attribute - %s/%s cmd: %s payload: %s" % (nwkid, EPout, cmd, payload)) def tuya_cmd(self, nwkid, EPout, cluster_frame, sqn, cmd, action, data, action2=None, data2=None): - self.log.logging("Tuya", "Debug", "tuya_cmd - %s/%s cmd: %s action: %s data: %s" % (nwkid, EPout, cmd, action, data)) + self.log.logging(["Tuya0601", "Tuya"], "Debug", "tuya_cmd - %s/%s cmd: %s action: %s data: %s" % (nwkid, EPout, cmd, action, data)) if nwkid not in self.ListOfDevices: return @@ -85,31 +85,20 @@ def tuya_cmd(self, nwkid, EPout, cluster_frame, sqn, cmd, action, data, action2= zigate_ep=ZIGATE_EP, ackIsDisabled=is_ack_tobe_disabled(self, nwkid), ) - self.log.logging("Tuya", "Debug", "tuya_cmd - %s/%s cmd: %s payload: %s" % (nwkid, EPout, cmd, payload)) + self.log.logging(["Tuya0601", "Tuya"], "Debug", "tuya_cmd - %s/%s cmd: %s payload: %s" % (nwkid, EPout, cmd, payload)) def store_tuya_attribute(self, NwkId, Attribute, Value): - if "Tuya" not in self.ListOfDevices[NwkId]: - self.ListOfDevices[NwkId]["Tuya"] = {} - self.ListOfDevices[NwkId]["Tuya"][Attribute] = Value + # Ensure "Tuya" key exists for the given NwkId and then store the attribute + tuya_device_info = self.ListOfDevices.setdefault(NwkId, {}).setdefault("Tuya", {}) + tuya_device_info[Attribute] = Value -def get_tuya_attribute(self, Nwkid, Attribute): - if "Tuya" not in self.ListOfDevices[Nwkid]: - return None - if Attribute not in self.ListOfDevices[Nwkid]["Tuya"]: - return None - return self.ListOfDevices[Nwkid]["Tuya"][Attribute] +def get_tuya_attribute(self, NwkId, Attribute): + return self.ListOfDevices.get(NwkId, {}).get("Tuya", {}).get(Attribute) def get_next_tuya_transactionId(self, NwkId): - if "Tuya" not in self.ListOfDevices[NwkId]: - self.ListOfDevices[NwkId]["Tuya"] = {} - - if "TuyaTransactionId" not in self.ListOfDevices[NwkId]["Tuya"]: - self.ListOfDevices[NwkId]["Tuya"]["TuyaTransactionId"] = 0x00 - - self.ListOfDevices[NwkId]["Tuya"]["TuyaTransactionId"] += 1 - if self.ListOfDevices[NwkId]["Tuya"]["TuyaTransactionId"] > 0xFF: - self.ListOfDevices[NwkId]["Tuya"]["TuyaTransactionId"] = 0x00 - return self.ListOfDevices[NwkId]["Tuya"]["TuyaTransactionId"] + tuya_info = self.ListOfDevices.setdefault(NwkId, {}).setdefault("Tuya", {}) + tuya_info["TuyaTransactionId"] = (tuya_info.get("TuyaTransactionId", 0x00) + 1) & 0xFF + return tuya_info["TuyaTransactionId"] diff --git a/Modules/zclClusterHelpers.py b/Modules/zclClusterHelpers.py index 4115d1a56..4747128c7 100644 --- a/Modules/zclClusterHelpers.py +++ b/Modules/zclClusterHelpers.py @@ -277,11 +277,17 @@ def _upd_data_strut_based_on_model(self, MsgSrcAddr, modelName, initial_ep): def _build_model_name( self, nwkid, modelName): - + + self.log.logging([ "ZclClusters", "Pairing"], "Debug", f"_build_model_name {modelName}", nwkid) + manufacturer_name = self.ListOfDevices[nwkid].get("Manufacturer Name", "") manuf_code = self.ListOfDevices[nwkid].get("Manufacturer", "") zdevice_id = self.ListOfDevices[nwkid].get("ZDeviceID", None) + self.log.logging([ "ZclClusters", "Pairing"], "Debug", f"_build_model_name manufacturer_name: {manufacturer_name}", nwkid) + self.log.logging([ "ZclClusters", "Pairing"], "Debug", f"_build_model_name manuf_code: {manuf_code}", nwkid) + self.log.logging([ "ZclClusters", "Pairing"], "Debug", f"_build_model_name zdevice_id: {zdevice_id}", nwkid) + if modelName in ( '66666', ): # https://github.com/Koenkk/zigbee2mqtt/issues/4338 return check_found_plugin_model( self, modelName, manufacturer_name=manufacturer_name, manufacturer_code=manuf_code, device_id=zdevice_id) diff --git a/OTAFirmware/NODON/.PRECIOUS b/OTAFirmware/NODON/.PRECIOUS new file mode 100644 index 000000000..e69de29bb diff --git a/Tools/generate_z4d_certificates.py b/Tools/generate_z4d_certificates.py new file mode 100755 index 000000000..178f092e3 --- /dev/null +++ b/Tools/generate_z4d_certificates.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Implementation of Zigbee for Domoticz plugin. +# +# This file is part of Zigbee for Domoticz plugin. https://github.com/zigbeefordomoticz/Domoticz-Zigbee +# (C) 2015-2024 +# +# Initial authors: zaraki673 & pipiche38 +# +# SPDX-License-Identifier: GPL-3.0 license + +""" +Script to generate a self-signed SSL/TLS certificate and demonstrate usage in an SSL context. + +Requirements: +- Python 3.x +- OpenSSL command-line tool (`openssl`) accessible in the system path. + +Functions: +- create_self_signed_cert(cert_dir): + Generates a self-signed SSL certificate and key pair if not already present. + +Usage: +1. Run the script to generate or retrieve the SSL certificate and key. +2. Use the generated certificate and key paths in an SSL context for secure communication. + +Example: + python3 generate_z4d_certificates.py + +Note: +- Modify the `-subj` parameter in the `openssl` command to customize certificate details. +- For production use, consider obtaining certificates from a trusted certificate authority (CA). +""" + +import os +import ssl +import subprocess + + +def create_self_signed_cert(cert_dir): + """ + Generate a self-signed SSL certificate and key pair if not already present. + + Args: + - cert_dir (str): Directory path where the certificate and key will be stored. + + Returns: + - cert_path (str): Path to the generated certificate file. + - key_path (str): Path to the generated private key file. + """ + + if not os.path.exists(cert_dir): + os.makedirs(cert_dir) + + # Paths for the certificate and key files + cert_path = os.path.join(cert_dir, "server.crt") + key_path = os.path.join(cert_dir, "server.key") + + # Check if the certificate already exists + if os.path.exists(cert_path) and os.path.exists(key_path): + print("Certificate and key already exist.") + return cert_path, key_path + + # Generate a self-signed certificate + subprocess.check_call([ + "openssl", "req", "-x509", "-nodes", "-days", "365", + "-newkey", "rsa:4096", "-keyout", key_path, + "-out", cert_path, + "-subj", "/C=FR/ST=California/L=Paris/O=Z4D/OU=Org/CN=localhost" + ]) + + print(f"Certificate and key generated: {cert_path}, {key_path}") + return cert_path, key_path + +# Directory to store the certificate and key +cert_dir = "./certs" + +# Create self-signed certificate +cert_path, key_path = create_self_signed_cert(cert_dir) + +# Example usage of the certificate in an SSL context +context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) +context.load_cert_chain(certfile=cert_path, keyfile=key_path) + +print("SSL context created with the generated certificate.") diff --git a/Z4D_decoders/z4d_decoder_IAS.py b/Z4D_decoders/z4d_decoder_IAS.py index 88c462e25..c7fe5a886 100644 --- a/Z4D_decoders/z4d_decoder_IAS.py +++ b/Z4D_decoders/z4d_decoder_IAS.py @@ -115,17 +115,24 @@ def Decode8401(self, Devices, MsgData, MsgLQI): if heiman_door_bell_button: self.log.logging('Input', 'Debug',f"Decode8401 HeimanDoorBellButton: {MsgSrcAddr} {MsgZoneStatus}", MsgSrcAddr) - if tamper: - MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0006', '01') + _heiman_door_bell_ef_3(self,Devices, MsgSrcAddr, MsgEp, MsgZoneStatus) return + self.log.logging('Input', 'Debug', 'IAS zone status change %s/%s %s alarm1: %s alarm2: %s tamper: %s' % ( + MsgSrcAddr, MsgEp, Model, alarm1, alarm2, tamper)) + motion_via_IAS_alarm = get_device_config_param(self, MsgSrcAddr, 'MotionViaIASAlarm1') self.log.logging('Input', 'Debug', 'MotionViaIASAlarm1 = %s' % motion_via_IAS_alarm) ias_alarm1_2_merged = get_deviceconf_parameter_value(self, Model, 'IASAlarmMerge', return_default=None) self.log.logging('Input', 'Debug', 'IASAlarmMerge = %s' % ias_alarm1_2_merged) - if ias_alarm1_2_merged: + if Model == "LDSENK08": + _ldsenk08_zone_status_change( self, Devices, MsgSrcAddr, MsgEp, MsgClusterId, MsgZoneStatus) + _update_ias_zone_status(self, MsgSrcAddr, MsgEp, MsgZoneStatus) + return + + elif ias_alarm1_2_merged: self.log.logging('Input', 'Debug', 'IASAlarmMerge alarm1 %s alarm2 %s' % (alarm1, alarm2)) combined_alarm = alarm2 << 1 | alarm1 self.log.logging('Input', 'Debug', 'IASAlarmMerge combined value = %02d' % combined_alarm) @@ -135,7 +142,7 @@ def Decode8401(self, Devices, MsgData, MsgLQI): self.log.logging('Input', 'Debug', 'Motion detected sending to MajDomo %s/%s %s' % (MsgSrcAddr, MsgEp, alarm1 or alarm2)) MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0406', '%02d' % (alarm1 or alarm2)) - elif self.ListOfDevices[MsgSrcAddr]['Model'] in ('lumi.sensor_magnet', 'lumi.sensor_magnet.aq2', 'lumi.sensor_magnet.acn001', 'lumi.magnet.acn001'): + elif Model in ('lumi.sensor_magnet', 'lumi.sensor_magnet.aq2', 'lumi.sensor_magnet.acn001', 'lumi.magnet.acn001'): MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0006', '%02d' % alarm1) elif Model not in ('RC-EF-3.0', 'RC-EM'): @@ -143,23 +150,78 @@ def Decode8401(self, Devices, MsgData, MsgLQI): if tamper: MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0009', '01') - else: MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0009', '00') if battery: self.log.logging('Input', 'Log', 'Decode8401 Low Battery or defective battery: Device: %s %s/%s' % (MsgSrcAddr, battdef, battery), MsgSrcAddr) self.ListOfDevices[MsgSrcAddr]['IASBattery'] = 5 - else: self.ListOfDevices[MsgSrcAddr]['IASBattery'] = 100 if 'IAS' in self.ListOfDevices[MsgSrcAddr] and 'ZoneStatus' in self.ListOfDevices[MsgSrcAddr]['IAS']: if not isinstance(self.ListOfDevices[MsgSrcAddr]['IAS']['ZoneStatus'], dict): self.ListOfDevices[MsgSrcAddr]['IAS']['ZoneStatus'] = {} - _update_ias_zone_status(self, MsgSrcAddr, MsgEp, MsgZoneStatus) +def _ldsenk08_zone_status_change( self, Devices, MsgSrcAddr, MsgEp, MsgClusterId, MsgZoneStatus): + zoneStatus = int(MsgZoneStatus, 16) + door_contact = zoneStatus & 1 + vibration = (zoneStatus & (1 << 1)) > 0 + tamper_bit = (zoneStatus & (1 << 2)) > 0 + batter_low = (zoneStatus & (1 << 3)) > 0 + + self.log.logging('Input', 'Log', '_ldsenk08_zone_status_change %s/%s door_contact: %s vibration: %s tamper_bit: %s' % ( + MsgSrcAddr, MsgEp, door_contact, vibration, tamper_bit)) + + # Door sensor (alarm1) + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, MsgClusterId, '%02d' % door_contact ) + + # Vibration (alarm2) + cluster_id = "0101" + attribute_id = "0055" + state = "20" if vibration else "00" + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, cluster_id, state, Attribute_=attribute_id, ) + + if tamper_bit: + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0009', '01') + else: + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, '0009', '00') + + self.ListOfDevices[MsgSrcAddr]['IASBattery'] = 5 if batter_low else 100 + + +def _heiman_door_bell_ef_3(self, Devices, MsgSrcAddr, MsgEp, MsgZoneStatus): + # https://github.com/zigbeefordomoticz/z4d-certified-devices/issues/55 + tamper_status_mapping = { + "0": ('0009', '00'), # Mounted + "4": ('0009', '01'), # Unmounted + } + + ring_status_mapping = { + "8": ('0006', '01'), # Ring + } + self.log.logging('Input', 'Debug', '_heiman_door_bell_ef_3 %s/%s %s' % (MsgSrcAddr, MsgEp, MsgZoneStatus)) + + # Check and update zone status + if MsgZoneStatus[3] in tamper_status_mapping: + # Tamper (Mount , umount) + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, *tamper_status_mapping[MsgZoneStatus[3]]) + + # Check and update ring status. Allow 3s between 2 rings + if MsgZoneStatus[0] in ring_status_mapping: + # Ring + device = self.ListOfDevices.setdefault(MsgSrcAddr, {}) + ep = device.setdefault('Ep', {}) + ep_details = ep.setdefault(MsgEp, {}) + heiman_door_bell = ep_details.setdefault('HeimanDoorBell', {}) + ring_time_stamp = heiman_door_bell.get('RingTimeStamp') + current_time = time.time() + + if ring_time_stamp is None or current_time > (ring_time_stamp + 3): + MajDomoDevice(self, Devices, MsgSrcAddr, MsgEp, *ring_status_mapping[MsgZoneStatus[0]]) + heiman_door_bell['RingTimeStamp'] = current_time + def _extract_zone_status_info(self, msg_data): MsgSQN = msg_data[:2] diff --git a/Z4D_decoders/z4d_decoder_Simple_Descriptor_Rsp.py b/Z4D_decoders/z4d_decoder_Simple_Descriptor_Rsp.py index a53c8cb70..54ca46ca6 100644 --- a/Z4D_decoders/z4d_decoder_Simple_Descriptor_Rsp.py +++ b/Z4D_decoders/z4d_decoder_Simple_Descriptor_Rsp.py @@ -36,11 +36,11 @@ def Decode8043(self, Devices, MsgData, MsgLQI): if MsgDataShAddr not in self.ListOfDevices: self.log.logging('Input', 'Error', 'Decode8043 - receive message for non existing device') return - if int(MsgDataProfile, 16) == 49246 and int(MsgDataDeviceId, 16) == 57694: + if int(MsgDataProfile, 16) == 49246 and int(MsgDataDeviceId, 16) == 57694: # DeviceID: 0xE15E self.log.logging('Input', 'Log', 'Decode8043 - Received ProfileID: %s, ZDeviceID: %s - skip' % (MsgDataProfile, MsgDataDeviceId)) if MsgDataEp in self.ListOfDevices[MsgDataShAddr]['Ep']: del self.ListOfDevices[MsgDataShAddr]['Ep'][MsgDataEp] - if 'NbEp' in self.ListOfDevices[MsgDataShAddr] and self.ListOfDevices[MsgDataShAddr]['NbEp'] > '1': + if 'NbEp' in self.ListOfDevices[MsgDataShAddr] and int(self.ListOfDevices[MsgDataShAddr]['NbEp']) > 1: self.ListOfDevices[MsgDataShAddr]['NbEp'] = int(self.ListOfDevices[MsgDataShAddr]['NbEp']) - 1 return if not inDB_status: @@ -130,4 +130,4 @@ def Decode8043(self, Devices, MsgData, MsgLQI): if request_next_Ep(self, MsgDataShAddr) and (not inDB_status): self.ListOfDevices[MsgDataShAddr]['Status'] = '8043' self.ListOfDevices[MsgDataShAddr]['Heartbeat'] = '0' - self.log.logging('Pairing', 'Debug', 'Decode8043 - Processed ' + MsgDataShAddr + ' end results is: ' + str(self.ListOfDevices[MsgDataShAddr])) \ No newline at end of file + self.log.logging('Pairing', 'Debug', 'Decode8043 - Processed ' + MsgDataShAddr + ' end results is: ' + str(self.ListOfDevices[MsgDataShAddr])) diff --git a/Z4D_decoders/z4d_decoder_config_reporting.py b/Z4D_decoders/z4d_decoder_config_reporting.py index 5979a5c98..4a226d9f0 100644 --- a/Z4D_decoders/z4d_decoder_config_reporting.py +++ b/Z4D_decoders/z4d_decoder_config_reporting.py @@ -35,8 +35,10 @@ def Decode8120(self, Devices, MsgData, MsgLQI): Decode8120_attribute(self, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttributeId, MsgStatus) def Decode8122(self, Devices, MsgData, MsgLQI): - self.configureReporting.read_report_configure_response(MsgData, MsgLQI) + if self.configureReporting: + self.configureReporting.read_report_configure_response(MsgData, MsgLQI) def Decode8120_attribute(self, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttributeId, MsgStatus): self.log.logging('Input', 'Debug', 'Decode8120 --> SQN: [%s], SrcAddr: %s, SrcEP: %s, ClusterID: %s, Attribute: %s Status: %s' % (MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttributeId, MsgStatus), MsgSrcAddr) - self.configureReporting.read_configure_reporting_response(MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttributeId, MsgStatus) \ No newline at end of file + if self.configureReporting: + self.configureReporting.read_configure_reporting_response(MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttributeId, MsgStatus) \ No newline at end of file diff --git a/Zigbee/zclDecoders.py b/Zigbee/zclDecoders.py index 6bd78fcd3..430055492 100644 --- a/Zigbee/zclDecoders.py +++ b/Zigbee/zclDecoders.py @@ -44,9 +44,9 @@ def zcl_decoders(self, SrcNwkId, SrcEndPoint, TargetEp, ClusterId, Payload, fram self.log.logging("zclDecoder", "Debug", "zcl_decoders Duplicate frame [%s] %s" %(Sqn, Payload)) return None - # Let's answer - self.log.logging("zclDecoder", "Debug", "zcl_decoders sending a default response for command %s" %(Command)) - zcl_raw_default_response( self, SrcNwkId, ZIGATE_EP, SrcEndPoint, ClusterId, Command, Sqn, command_status="00", manufcode=ManufacturerCode, orig_fcf=fcf ) + # Let's answer , Since 7.1.12 zigpy is handling the default response, so no need to do it + #self.log.logging("zclDecoder", "Debug", "zcl_decoders sending a default response for command %s" %(Command)) + #zcl_raw_default_response( self, SrcNwkId, ZIGATE_EP, SrcEndPoint, ClusterId, Command, Sqn, command_status="00", manufcode=ManufacturerCode, orig_fcf=fcf ) self.log.logging("zclDecoder", "Debug", "zcl_decoders Zcl.ddr: %s GlobalCommand: %s Sqn: %s ManufCode: %s Command: %s Data: %s Payload: %s" %( default_response_disable, GlobalCommand, Sqn, ManufacturerCode, Command, Data, Payload)) diff --git a/Zigbee/zclRawCommands.py b/Zigbee/zclRawCommands.py index c69265c93..749f2ae0c 100644 --- a/Zigbee/zclRawCommands.py +++ b/Zigbee/zclRawCommands.py @@ -172,7 +172,7 @@ def zcl_raw_default_response( self, nwkid, EPin, EPout, cluster, response_to_com payload += sqn + cmd + response_to_command + command_status self.log.logging("zclCommand", "Debug", f"zcl_raw_default_response ==== payload: {payload}") - raw_APS_request(self, nwkid, EPout, cluster, "0104", payload, zigpyzqn=sqn, zigate_ep=EPin, ackIsDisabled=is_ack_tobe_disabled(self, nwkid)) + raw_APS_request(self, nwkid, EPout, cluster, "0104", payload, zigpyzqn=sqn, zigate_ep=EPin, highpriority=True, ackIsDisabled=is_ack_tobe_disabled(self, nwkid)) return sqn diff --git a/constraints.txt b/constraints.txt index 5dfee4090..eb37ff632 100644 --- a/constraints.txt +++ b/constraints.txt @@ -7,4 +7,4 @@ dnspython==2.6.1 pyserial>=3.5 charset-normalizer==2.0.11 jsonschema==4.17.3 -cryptography<=40.0.2 +cryptography<=40.0.2 \ No newline at end of file diff --git a/plugin.py b/plugin.py index d05d3c61c..730357a56 100644 --- a/plugin.py +++ b/plugin.py @@ -309,10 +309,10 @@ def onStart(self): _current_python_version_major = sys.version_info.major _current_python_version_minor = sys.version_info.minor - Domoticz.Status( "Z4D requires python3.8 or above and you are running %s.%s" %( + Domoticz.Status( "Z4D requires python3.9 or above and you are running %s.%s" %( _current_python_version_major, _current_python_version_minor)) - assert sys.version_info >= (3, 8) # nosec + assert sys.version_info >= (3, 9) # nosec if Parameters["Mode1"] == "V1" and Parameters["Mode2"] in ( "USB", "DIN", "PI", "Wifi", ): self.transport = Parameters["Mode2"] @@ -485,7 +485,7 @@ def onStart(self): ) self.WebUsername, self.WebPassword = self.domoticzdb_Preferences.retreiveWebUserNamePassword() - self.adminWidgets = AdminWidgets( self.log , self.pluginconf, self.pluginParameters, self.ListOfDomoticzWidget, Devices, self.ListOfDevices, self.HardwareID) + self.adminWidgets = AdminWidgets( self.log , self.pluginconf, self.pluginParameters, self.ListOfDomoticzWidget, Devices, self.ListOfDevices, self.HardwareID, self.IEEE2NWK) self.adminWidgets.updateStatusWidget(Devices, "Starting up") self.DeviceListName = "DeviceList-" + str(Parameters["HardwareID"]) + ".txt" @@ -597,6 +597,11 @@ def onStop(self): None """ Domoticz.Log("onStop()") + + # Flush ListOfDevices + if self.log: + self.log.logging("Plugin", "Log", "Flushing plugin database onto disk") + WriteDeviceList(self, 0) # write immediatly # Uninstall Z4D custom UI from Domoticz uninstall_Z4D_to_domoticz_custom_ui() @@ -619,11 +624,11 @@ def onStop(self): self.webserver.onStop() # Save plugin database - if self.pluginconf: + if self.PDMready and self.pluginconf: WriteDeviceList(self, 0) # Print and save statistics if configured - if self.pluginconf and self.statistics: + if self.PDMready and self.pluginconf and self.statistics: self.statistics.printSummary() self.statistics.writeReport() @@ -835,7 +840,7 @@ def onDisconnect(self, Connection): def onHeartbeat(self): - if not self.VersionNewFashion or self.pluginconf is None: + if not self.VersionNewFashion or self.pluginconf is None or self.log is None: # Not yet ready return @@ -971,7 +976,7 @@ def retreive_zigpy_topology_data(self): def start_zigbee_transport(self ): if self.transport in ("USB", "DIN", "V2-DIN", "V2-USB"): - check_python_modules_version( self ) + check_python_modules_version( self ) _start_native_usb_zigate(self) elif self.transport in ("PI", "V2-PI"): @@ -1022,7 +1027,7 @@ def _start_native_wifi_zigate(self): def _start_native_zigate(self, serialPort=None, wifiAddress=None, wifiPort=None): from Classes.ZigateTransport.Transport import ZigateTransport - check_python_modules_version(self) + check_python_modules_version(self ) self.pluginconf.pluginConf["ControllerInRawMode"] = False self.zigbee_communication = "native" self.pluginParameters["Zigpy"] = False diff --git a/requirements.txt b/requirements.txt index 7b1754500..5accfbfb8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ pyserial-asyncio-fast zigpy_znp zigpy_deconz bellows +requests diff --git a/www/z4d/12.3967806234088415.js b/www/z4d/12.3967806234088415.js deleted file mode 100644 index 7ecf3ba97..000000000 --- a/www/z4d/12.3967806234088415.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkz4d_plugin=self.webpackChunkz4d_plugin||[]).push([[12],{55012:(J,F,r)=>{r.r(F),r.d(F,{DeviceModule:()=>H});var l=r(89417),g=r(93887),d=r(93331),u=r(38117),e=r(54438),_=r(3366),m=r(19664),v=r(88652),h=r(45794),f=r(83801),E=r(60177),p=r(46247),y=r(5779),k=r(22242),j=r(81141);let I=(()=>{class n{iconName;static \u0275fac=function(a){return new(a||n)};static \u0275cmp=e.VBU({type:n,selectors:[["shared-custom-icon"]],inputs:{iconName:"iconName"},decls:5,vars:1,consts:[["preserveAspectRatio","xMidYMid meet","viewBox","0 0 64 64",1,"w-25"]],template:function(a,i){1&a&&(e.qSk(),e.j41(0,"svg",0),e.EFF(1,"\n "),e.nrm(2,"use"),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n")),2&a&&(e.R7$(2),e.BMQ("href","assets/icons.svg#"+i.iconName,null,"xlink"))},encapsulation:2})}return n})();const T=()=>["_NwkId","IEEE","Model","WidgetList","ZDeviceName","MacCapa","Status","Health"],C=()=>[10,25,50];function N(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",14),e.EFF(2,"\n "),e.j41(3,"span",15),e.EFF(4,"\n "),e.nrm(5,"i",16),e.EFF(6,"\n "),e.j41(7,"input",17),e.nI1(8,"translate"),e.bIt("input",function(i){e.eBV(t),e.XpG();const o=e.sdS(18);return e.Njj(o.filterGlobal(i.target.value,"contains"))}),e.k0s(),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n ")}if(2&n){e.XpG();const t=e.sdS(18);e.R7$(7),e.FS9("placeholder",e.bMT(8,2,"device.byname.placeholder")),e.Y8G("value",null==t.filters.global?null:t.filters.global.value)}}function D(n,c){1&n&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"th",18),e.EFF(4),e.nI1(5,"translate"),e.k0s(),e.EFF(6,"\n "),e.j41(7,"th",18),e.EFF(8),e.nI1(9,"translate"),e.k0s(),e.EFF(10,"\n "),e.j41(11,"th",19),e.EFF(12),e.nI1(13,"translate"),e.nrm(14,"p-sortIcon",20),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n "),e.j41(17,"th",21),e.EFF(18),e.nI1(19,"translate"),e.nrm(20,"p-sortIcon",22),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"th",23),e.EFF(24),e.nI1(25,"translate"),e.nrm(26,"p-sortIcon",24),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.j41(29,"th",25),e.EFF(30),e.nI1(31,"translate"),e.nrm(32,"p-sortIcon",26),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.j41(35,"th",27),e.EFF(36),e.nI1(37,"translate"),e.nrm(38,"p-sortIcon",28),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.j41(41,"th",29),e.EFF(42),e.nI1(43,"translate"),e.nrm(44,"p-sortIcon",30),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.j41(47,"th",31),e.EFF(48),e.nI1(49,"translate"),e.nrm(50,"p-sortIcon",32),e.EFF(51,"\n "),e.k0s(),e.EFF(52,"\n "),e.j41(53,"th",33),e.EFF(54),e.nI1(55,"translate"),e.nrm(56,"p-sortIcon",34),e.EFF(57,"\n "),e.k0s(),e.EFF(58,"\n "),e.j41(59,"th",35),e.EFF(60),e.nI1(61,"translate"),e.nrm(62,"p-sortIcon",36),e.EFF(63,"\n "),e.k0s(),e.EFF(64,"\n "),e.j41(65,"th",37),e.EFF(66),e.nI1(67,"translate"),e.k0s(),e.EFF(68,"\n "),e.k0s(),e.EFF(69,"\n ")),2&n&&(e.R7$(4),e.SpI("\n ",e.bMT(5,12,"device.byname.trash.column"),"\n "),e.R7$(4),e.SpI("\n ",e.bMT(9,14,"device.byname.optimized.column"),"\n "),e.R7$(4),e.SpI("\n ",e.bMT(13,16,"device.byname.shortid.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(19,18,"device.byname.ieee.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(25,20,"device.byname.model.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(31,22,"device.byname.widget.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(37,24,"device.byname.devicename.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(43,26,"device.byname.capabilities.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(49,28,"device.byname.lqi.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(55,30,"device.byname.status.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(61,32,"device.byname.health.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(67,34,"device.byname.devicename.param"),"\n "))}function R(n,c){if(1&n&&e.nrm(0,"button",46),2&n){const t=e.XpG(),i=t.expanded;e.Y8G("pRowToggler",t.$implicit)("icon",i?"pi pi-chevron-down":"pi pi-chevron-right")}}function B(n,c){if(1&n){const t=e.RV6();e.j41(0,"i",47),e.nI1(1,"translate"),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG(),s=e.sdS(34);return o.rowToDelete=i,e.Njj(o.open(s))}),e.k0s()}2&n&&e.FS9("title",e.bMT(1,1,"device.byname.delete.colum"))}function w(n,c){if(1&n){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"div",48),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG();return e.Njj(o.copy(i))}),e.EFF(3,"\n "),e.j41(4,"div",49),e.EFF(5,"\n "),e.j41(6,"shared-custom-icon",50),e.nI1(7,"translate"),e.nI1(8,"translate"),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.bVm()}2&n&&(e.R7$(6),e.FS9("ngbPopover",e.bMT(7,2,"device.byname.optimized.popover.text.ok")),e.FS9("popoverTitle",e.bMT(8,4,"device.byname.optimized.popover.title.ok")))}function M(n,c){if(1&n){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"div",48),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG();return e.Njj(o.copy(i))}),e.EFF(3,"\n "),e.j41(4,"div",49),e.EFF(5,"\n "),e.j41(6,"shared-custom-icon",51),e.nI1(7,"translate"),e.nI1(8,"translate"),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.bVm()}2&n&&(e.R7$(6),e.FS9("ngbPopover",e.bMT(7,2,"device.byname.optimized.popover.text.ko")),e.FS9("popoverTitle",e.bMT(8,4,"device.byname.optimized.popover.title.ko")))}function S(n,c){if(1&n&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&n){const t=c.$implicit;e.R7$(),e.SpI("\n ",t,"\n ")}}function $(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",52),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG().$implicit;return e.DH7(o.ZDeviceName,i)||(o.ZDeviceName=i),e.Njj(i)}),e.bIt("input",function(){e.eBV(t);const i=e.XpG(2);return e.Njj(i.hasEditing=!0)}),e.k0s(),e.EFF(2,"\n ")}if(2&n){const t=e.XpG().$implicit;e.R7$(),e.R50("ngModel",t.ZDeviceName)}}function x(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",52),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG().$implicit;return e.DH7(o.ZDeviceName,i)||(o.ZDeviceName=i),e.Njj(i)}),e.bIt("input",function(){e.eBV(t);const i=e.XpG(2);return e.Njj(i.hasEditing=!0)}),e.k0s(),e.EFF(2,"\n ")}if(2&n){const t=e.XpG().$implicit;e.R7$(),e.R50("ngModel",t.ZDeviceName)}}function G(n,c){if(1&n&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&n){const t=c.$implicit;e.R7$(),e.SpI("\n ",t,"\n ")}}function V(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td"),e.EFF(4,"\n "),e.DNE(5,R,1,2,"button",38),e.EFF(6,"\n "),e.DNE(7,B,2,3,"i",39),e.EFF(8,"\n "),e.k0s(),e.EFF(9,"\n "),e.j41(10,"td"),e.EFF(11,"\n "),e.DNE(12,w,13,6,"ng-container",40),e.EFF(13,"\n "),e.DNE(14,M,13,6,"ng-container",40),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n "),e.j41(17,"td"),e.EFF(18),e.k0s(),e.EFF(19,"\n "),e.j41(20,"td"),e.EFF(21),e.k0s(),e.EFF(22,"\n "),e.j41(23,"td"),e.EFF(24),e.k0s(),e.EFF(25,"\n "),e.j41(26,"td"),e.EFF(27,"\n "),e.DNE(28,S,2,1,"div",41),e.EFF(29,"\n "),e.k0s(),e.EFF(30,"\n "),e.j41(31,"td",42),e.EFF(32,"\n "),e.j41(33,"p-cellEditor"),e.EFF(34,"\n "),e.DNE(35,$,3,1,"ng-template",43),e.EFF(36,"\n "),e.DNE(37,x,3,1,"ng-template",44),e.EFF(38,"\n "),e.k0s(),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.j41(41,"td"),e.EFF(42,"\n "),e.DNE(43,G,2,1,"div",41),e.EFF(44,"\n "),e.k0s(),e.EFF(45,"\n "),e.j41(46,"td"),e.EFF(47),e.k0s(),e.EFF(48,"\n "),e.j41(49,"td"),e.EFF(50),e.k0s(),e.EFF(51,"\n "),e.j41(52,"td"),e.EFF(53),e.k0s(),e.EFF(54,"\n "),e.j41(55,"td"),e.EFF(56,"\n "),e.j41(57,"i",45),e.nI1(58,"translate"),e.nI1(59,"translate"),e.bIt("click",function(){const i=e.eBV(t).$implicit,o=e.XpG(),s=e.sdS(37);return o.rowParameter=i,e.Njj(o.editParameter(s))}),e.k0s(),e.EFF(60,"\n "),e.k0s(),e.EFF(61,"\n "),e.k0s(),e.EFF(62,"\n ")}if(2&n){const t=c.$implicit;e.R7$(5),e.Y8G("ngIf","{}"!==t.Param),e.R7$(2),e.Y8G("ngIf","not in DZ"===t.ConsistencyCheck||"Bad Pairing"===t.ConsistencyCheck||!t.WidgetList||0===t.WidgetList.length),e.R7$(5),e.Y8G("ngIf",t.CertifiedDevice),e.R7$(2),e.Y8G("ngIf",!t.CertifiedDevice),e.R7$(4),e.JRh(t._NwkId),e.R7$(3),e.JRh(t.IEEE),e.R7$(3),e.JRh(t.Model),e.R7$(4),e.Y8G("ngForOf",t.WidgetList),e.R7$(3),e.Y8G("pEditableColumn",t.ZDeviceName),e.R7$(12),e.Y8G("ngForOf",t.MacCapa),e.R7$(4),e.JRh(t.LQI),e.R7$(3),e.JRh(t.Status),e.R7$(3),e.JRh(t.Health),e.R7$(4),e.xc7("color",t.CheckParam?"orange":"green"),e.FS9("ngbPopover",e.bMT(58,17,"device.byname.parameter.popover.text")),e.FS9("popoverTitle",e.bMT(59,19,"device.byname.parameter.popover.title"))}}function P(n,c){if(1&n&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td",53),e.EFF(4,"\n "),e.j41(5,"div",54),e.EFF(6,"\n "),e.j41(7,"div"),e.EFF(8,"\n "),e.j41(9,"strong"),e.EFF(10),e.nI1(11,"translate"),e.k0s(),e.EFF(12),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n "),e.k0s(),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n ")),2&n){const t=c.$implicit;e.R7$(10),e.SpI("",e.bMT(11,2,"device.byname.devicename.param")," : "),e.R7$(2),e.SpI(" ",t.Param,"\n ")}}function X(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",55),e.EFF(2,"\n "),e.nrm(3,"h4",56),e.EFF(4,"\n "),e.j41(5,"button",57),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",58),e.EFF(9,"\n "),e.j41(10,"div",59),e.EFF(11,"\n "),e.j41(12,"button",60),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("erase"))}),e.k0s(),e.EFF(13,"\n "),e.j41(14,"button",61),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("cancel"))}),e.k0s(),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n")}}function O(n,c){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",55),e.EFF(2,"\n "),e.nrm(3,"h4",62),e.EFF(4,"\n "),e.j41(5,"button",57),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("cancel"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.j41(8,"div",63),e.EFF(9,"\n "),e.nrm(10,"div",64),e.nI1(11,"translate"),e.EFF(12,"\n "),e.j41(13,"div",65),e.EFF(14,"\n "),e.j41(15,"input",66),e.bIt("click",function(){e.eBV(t);const i=e.XpG();return e.Njj(i.onChangeEnabled())}),e.k0s(),e.EFF(16,"\n "),e.nrm(17,"label",67),e.EFF(18,"\n "),e.k0s(),e.EFF(19,"\n "),e.j41(20,"div",68),e.EFF(21),e.nI1(22,"translate"),e.k0s(),e.EFF(23,"\n "),e.j41(24,"textarea",69),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG();return e.DH7(o.parameter,i)||(o.parameter=i),e.Njj(i)}),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.j41(27,"div",59),e.EFF(28,"\n "),e.j41(29,"button",70),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("cancel"))}),e.k0s(),e.EFF(30,"\n "),e.j41(31,"button",71),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("save"))}),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n")}if(2&n){const t=e.XpG();e.R7$(10),e.Y8G("innerHTML",e.bMT(11,4,"device.byname.parameter.alert.subject"),e.npT),e.R7$(5),e.Y8G("checked",t.enabled),e.R7$(6),e.SpI("",e.bMT(22,6,"device.byname.devicename.param")," :"),e.R7$(3),e.R50("ngModel",t.parameter)}}const b=new u.Vy("DeviceByNameComponent");let L=(()=>{class n{apiService;translate;modalService;toastr;clipboard;devices;rows=[];temp=[];hasEditing=!1;rowToDelete;rowParameter;parameter;expanded={};enabled=!1;prefixEnabled="Disabled";enabledTrue="'Disabled': 0";enabledFalse="'Disabled': 1";constructor(t,a,i,o,s){this.apiService=t,this.translate=a,this.modalService=i,this.toastr=o,this.clipboard=s}ngOnChanges(t){t.devices.currentValue!==t.devices.previousValue&&(this.devices=this.devices,this.rows=this.devices,this.temp=[...this.rows])}open(t){this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then(()=>{this.delete()})}editParameter(t){this.parameter=this.rowParameter.Param,this.enabled=!this.parameter.includes(this.enabledFalse),this.enabled?(this.parameter=this.parameter.replace(this.enabledTrue.concat(","),""),this.parameter=this.parameter.replace(this.enabledTrue,"")):(this.parameter=this.parameter.replace(this.enabledFalse.concat(","),""),this.parameter=this.parameter.replace(this.enabledFalse,"")),this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then(()=>{this.parameter.includes(this.prefixEnabled)?this.toastr.error(this.translate.instant("device.byname.error.notify")):(this.parameter=this.parameter.replace("{",this.enabled?"{".concat(this.enabledTrue).concat(", "):"{".concat(this.enabledFalse).concat(", ")),this.updateValueJson(this.parameter,"Param",this.rowParameter._NwkId))})}onChangeEnabled(){this.enabled=!this.enabled}delete(){this.apiService.deleteZDeviceName(this.rowToDelete._NwkId).subscribe(()=>{const t=this.rows.indexOf(this.rowToDelete,0);this.rowToDelete=null,t>-1&&(this.rows.splice(t,1),this.rows=[...this.rows],this.temp=[...this.rows])})}updateValue(t,a,i){this.updateValueJson(t.target.value,a,i)}updateValueJson(t,a,i){this.hasEditing=!0;const o=this.rows.find(s=>s._NwkId===i);o?o[a]=t:b.error("row not found")}updateDevices(){this.apiService.putZDeviceName(this.rows).subscribe(t=>{b.debug(t),this.hasEditing=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}copy(t){this.apiService.getNonOptimizedDevice(t._NwkId).subscribe(a=>this.clipboard.copy(JSON.stringify(a)))}static \u0275fac=function(a){return new(a||n)(e.rXU(_.G),e.rXU(m.c$),e.rXU(v.Bq),e.rXU(h.tw),e.rXU(f.B0))};static \u0275cmp=e.VBU({type:n,selectors:[["app-device-by-name"]],inputs:{devices:"devices"},features:[e.OA$],decls:39,vars:26,consts:[["dt1",""],["content",""],["editContent",""],[1,"card"],[1,"card-header","fw-bold"],[1,"btn","btn-primary","float-end",3,"click","disabled","translate"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],["styleClass","p-datatable-sm","dataKey","_NwkId","responsiveLayout","scroll","stateStorage","local","stateKey","device",3,"globalFilterFields","rowHover","showCurrentPageReport","currentPageReportTemplate","rowsPerPageOptions","value","rows","paginator","scrollable"],["pTemplate","caption"],["pTemplate","header"],["pTemplate","body"],["pTemplate","rowexpansion"],[1,"flex"],[1,"p-input-icon-left","ml-auto"],[1,"pi","pi-search"],["pInputText","","type","text",3,"input","value","placeholder"],[2,"width","1rem"],["pSortableColumn","_NwkId",2,"width","7rem"],["field","_NwkId"],["pSortableColumn","IEEE",2,"width","5rem"],["field","IEEE"],["pSortableColumn","Model",2,"width","13rem"],["field","Model"],["pSortableColumn","WidgetList",2,"width","15rem"],["field","WidgetList"],["pSortableColumn","ZDeviceName",2,"width","20rem"],["field","ZDeviceName"],["pSortableColumn","MacCapa",2,"width","10rem"],["field","MacCapa"],["pSortableColumn","LQI",2,"width","5rem"],["field","LQI"],["pSortableColumn","Status",2,"width","7rem"],["field","Status"],["pSortableColumn","Health",2,"width","6rem"],["field","Health"],[2,"width","2rem"],["type","button","pButton","","pRipple","","class","p-button-text p-button-rounded p-button-plain",3,"pRowToggler","icon",4,"ngIf"],["class","fa fa-trash","style","cursor: pointer",3,"title","click",4,"ngIf"],[4,"ngIf"],[4,"ngFor","ngForOf"],["pEditableColumnField","ZDeviceName",3,"pEditableColumn"],["pTemplate","input"],["pTemplate","output"],["triggers","mouseenter:mouseleave",1,"fas","fa-cog",2,"cursor","pointer",3,"click","ngbPopover","popoverTitle"],["type","button","pButton","","pRipple","",1,"p-button-text","p-button-rounded","p-button-plain",3,"pRowToggler","icon"],[1,"fa","fa-trash",2,"cursor","pointer",3,"click","title"],[3,"click"],[1,"container"],["triggers","mouseenter:mouseleave","iconName","CHECK_ICON",1,"container__icon","container__icon--green",3,"ngbPopover","popoverTitle"],["triggers","mouseenter:mouseleave","iconName","X_ICON",1,"container__icon","container__icon--orange",3,"ngbPopover","popoverTitle"],["pInputText","","type","text",3,"ngModelChange","input","ngModel"],["colspan","12"],[2,"padding-left","35px"],[1,"modal-header"],["id","modal-basic-title","translate","device.byname.alert.title",1,"modal-title"],["type","button","aria-label","Close",1,"btn-close",3,"click"],["translate","device.byname.alert.subject",1,"modal-body"],[1,"modal-footer"],["type","button","translate","device.byname.alert.delete",1,"btn","btn-primary",3,"click"],["type","button","translate","device.byname.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","device.byname.parameter.alert.title",1,"modal-title"],[1,"modal-body"],[3,"innerHTML"],[1,"switch","switch-sm","mt-3","me-2","pe-3"],["type","checkbox","id","switch-enabled",3,"click","checked"],["for","switch-enabled","translate","device.byname.devicename.enabled",1,"mb-0"],[1,"mt-3"],["name","parameter","rows","5",3,"ngModelChange","ngModel"],["type","button","translate","device.byname.parameter.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["type","button","translate","device.byname.parameter.alert.save",1,"btn","btn-primary",3,"click"]],template:function(a,i){if(1&a){const o=e.RV6();e.j41(0,"div",3),e.EFF(1,"\n "),e.j41(2,"div",4),e.EFF(3),e.nI1(4,"translate"),e.j41(5,"button",5),e.nI1(6,"translate"),e.bIt("click",function(){return e.eBV(o),e.Njj(i.updateDevices())}),e.k0s(),e.EFF(7,"\n "),e.k0s(),e.EFF(8,"\n "),e.j41(9,"div",6),e.EFF(10,"\n "),e.nrm(11,"p",7),e.nI1(12,"translate"),e.nI1(13,"translate"),e.EFF(14,"\n "),e.j41(15,"div",8),e.EFF(16,"\n "),e.j41(17,"p-table",9,0),e.nI1(19,"translate"),e.EFF(20,"\n "),e.DNE(21,N,12,4,"ng-template",10),e.EFF(22,"\n "),e.DNE(23,D,70,36,"ng-template",11),e.EFF(24,"\n "),e.DNE(25,V,63,21,"ng-template",12),e.EFF(26,"\n "),e.DNE(27,P,17,4,"ng-template",13),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.k0s(),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n"),e.k0s(),e.EFF(32,"\n\n"),e.DNE(33,X,17,0,"ng-template",null,1,e.C5r),e.EFF(35,"\n\n"),e.DNE(36,O,34,8,"ng-template",null,2,e.C5r),e.EFF(38,"\n")}2&a&&(e.R7$(3),e.SpI("\n ",e.bMT(4,14,"device.byname.header"),"\n "),e.R7$(2),e.FS9("translate",e.bMT(6,16,"device.byname.validate.button")),e.Y8G("disabled",!i.hasEditing),e.R7$(6),e.Y8G("innerHTML",e.bMT(12,18,"group.create.subtitle"),e.npT)("innerHTML",e.bMT(13,20,"device.byname.subtitle"),e.npT),e.R7$(6),e.FS9("currentPageReportTemplate",e.bMT(19,22,"TOTAL")),e.Y8G("globalFilterFields",e.lJ4(24,T))("rowHover",!0)("showCurrentPageReport",!0)("rowsPerPageOptions",e.lJ4(25,C))("value",i.rows)("rows",10)("paginator",!0)("scrollable",!0))},dependencies:[E.Sq,E.bT,l.me,l.BC,l.vS,v.ZM,m.Mm,p.XI,y.Ei,p.Tg,p.FP,p.hp,p.c5,p.yc,k.S,j._f,I,m.D9],styles:[".container[_ngcontent-%COMP%]{display:flex}.container--green[_ngcontent-%COMP%]{color:green}.container--primary-color[_ngcontent-%COMP%]{color:var(--primary-color)}.container__icon[_ngcontent-%COMP%]{flex:1}.container__icon--orange[_ngcontent-%COMP%]{color:orange}.container__icon--green[_ngcontent-%COMP%]{color:green}textarea[_ngcontent-%COMP%]{width:100%}"]})}return n})();const Y=[{path:"",component:(()=>{class n{apiService;formBuilder;translate;form;devices;constructor(t,a,i){this.apiService=t,this.formBuilder=a,this.translate=i}ngOnInit(){this.form=this.formBuilder.group({devices:this.formBuilder.group({}),permit:this.formBuilder.group({})}),this.apiService.getZDeviceName().subscribe(t=>{this.devices=t})}static \u0275fac=function(a){return new(a||n)(e.rXU(_.G),e.rXU(l.ok),e.rXU(m.c$))};static \u0275cmp=e.VBU({type:n,selectors:[["app-device"]],decls:5,vars:2,consts:[[3,"formGroup"],[3,"devices"]],template:function(a,i){1&a&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.nrm(2,"app-device-by-name",1),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n")),2&a&&(e.Y8G("formGroup",i.form),e.R7$(2),e.Y8G("devices",i.devices))},dependencies:[l.qT,l.cb,l.j4,L]})}return n})(),data:{title:(0,u.o6)("device")}}];let Z=(()=>{class n{static \u0275fac=function(a){return new(a||n)};static \u0275mod=e.$C({type:n});static \u0275inj=e.G2t({imports:[d.iI.forChild(Y),d.iI]})}return n})(),H=(()=>{class n{static \u0275fac=function(a){return new(a||n)};static \u0275mod=e.$C({type:n});static \u0275inj=e.G2t({imports:[Z,g.G,l.YN]})}return n})()}}]); \ No newline at end of file diff --git a/www/z4d/12.445878b6b97c587c.js b/www/z4d/12.445878b6b97c587c.js new file mode 100644 index 000000000..b93f7a9fe --- /dev/null +++ b/www/z4d/12.445878b6b97c587c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkz4d_plugin=self.webpackChunkz4d_plugin||[]).push([[12],{55012:(z,F,c)=>{c.r(F),c.d(F,{DeviceModule:()=>U});var l=c(89417),g=c(93887),d=c(93331),_=c(38117),e=c(54438),u=c(3366),m=c(19664),v=c(88652),h=c(45794),f=c(83801),E=c(60177),p=c(46247),y=c(5779),k=c(22242),I=c(81141);let j=(()=>{class n{iconName;static \u0275fac=function(a){return new(a||n)};static \u0275cmp=e.VBU({type:n,selectors:[["shared-custom-icon"]],inputs:{iconName:"iconName"},decls:5,vars:1,consts:[["preserveAspectRatio","xMidYMid meet","viewBox","0 0 64 64",1,"w-25"]],template:function(a,i){1&a&&(e.qSk(),e.j41(0,"svg",0),e.EFF(1,"\n "),e.nrm(2,"use"),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n")),2&a&&(e.R7$(2),e.BMQ("href","assets/icons.svg#"+i.iconName,null,"xlink"))},encapsulation:2})}return n})();const C=()=>["_NwkId","IEEE","Model","WidgetList","ZDeviceName","MacCapa","Status","Health"],T=()=>[10,25,50];function N(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",14),e.EFF(2,"\n "),e.j41(3,"span",15),e.EFF(4,"\n "),e.nrm(5,"i",16),e.EFF(6,"\n "),e.j41(7,"input",17),e.nI1(8,"translate"),e.bIt("input",function(i){e.eBV(t),e.XpG();const o=e.sdS(18);return e.Njj(o.filterGlobal(i.target.value,"contains"))}),e.k0s(),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n ")}if(2&n){e.XpG();const t=e.sdS(18);e.R7$(7),e.FS9("placeholder",e.bMT(8,2,"device.byname.placeholder")),e.Y8G("value",null==t.filters.global?null:t.filters.global.value)}}function D(n,r){1&n&&(e.EFF(0,"\n "),e.j41(1,"th",38),e.EFF(2),e.nI1(3,"translate"),e.nrm(4,"p-sortIcon",39),e.EFF(5,"\n "),e.k0s(),e.EFF(6,"\n ")),2&n&&(e.R7$(2),e.SpI("\n ",e.bMT(3,1,"device.byname.rssi.column"),""))}function R(n,r){if(1&n&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"th",18),e.EFF(4),e.nI1(5,"translate"),e.k0s(),e.EFF(6,"\n "),e.j41(7,"th",18),e.EFF(8),e.nI1(9,"translate"),e.k0s(),e.EFF(10,"\n "),e.j41(11,"th",19),e.EFF(12),e.nI1(13,"translate"),e.nrm(14,"p-sortIcon",20),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n "),e.j41(17,"th",21),e.EFF(18),e.nI1(19,"translate"),e.nrm(20,"p-sortIcon",22),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"th",23),e.EFF(24),e.nI1(25,"translate"),e.nrm(26,"p-sortIcon",24),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.j41(29,"th",25),e.EFF(30),e.nI1(31,"translate"),e.nrm(32,"p-sortIcon",26),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.j41(35,"th",27),e.EFF(36),e.nI1(37,"translate"),e.nrm(38,"p-sortIcon",28),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.j41(41,"th",29),e.EFF(42),e.nI1(43,"translate"),e.nrm(44,"p-sortIcon",30),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.j41(47,"th",31),e.EFF(48),e.nI1(49,"translate"),e.nrm(50,"p-sortIcon",32),e.EFF(51,"\n "),e.k0s(),e.EFF(52,"\n "),e.DNE(53,D,7,3),e.j41(54,"th",33),e.EFF(55),e.nI1(56,"translate"),e.nrm(57,"p-sortIcon",34),e.EFF(58,"\n "),e.k0s(),e.EFF(59,"\n "),e.j41(60,"th",35),e.EFF(61),e.nI1(62,"translate"),e.nrm(63,"p-sortIcon",36),e.EFF(64,"\n "),e.k0s(),e.EFF(65,"\n "),e.j41(66,"th",37),e.EFF(67),e.nI1(68,"translate"),e.k0s(),e.EFF(69,"\n "),e.k0s(),e.EFF(70,"\n ")),2&n){const t=e.XpG();e.R7$(4),e.SpI("\n ",e.bMT(5,13,"device.byname.trash.column"),"\n "),e.R7$(4),e.SpI("\n ",e.bMT(9,15,"device.byname.optimized.column"),"\n "),e.R7$(4),e.SpI("\n ",e.bMT(13,17,"device.byname.shortid.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(19,19,"device.byname.ieee.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(25,21,"device.byname.model.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(31,23,"device.byname.widget.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(37,25,"device.byname.devicename.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(43,27,"device.byname.capabilities.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(49,29,"device.byname.lqi.column"),""),e.R7$(5),e.vxM(53,t.showRSSI?53:-1),e.R7$(2),e.SpI("\n ",e.bMT(56,31,"device.byname.status.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(62,33,"device.byname.health.column"),""),e.R7$(6),e.SpI("\n ",e.bMT(68,35,"device.byname.devicename.param"),"\n ")}}function S(n,r){if(1&n&&e.nrm(0,"button",48),2&n){const t=e.XpG(),i=t.expanded;e.Y8G("pRowToggler",t.$implicit)("icon",i?"pi pi-chevron-down":"pi pi-chevron-right")}}function w(n,r){if(1&n){const t=e.RV6();e.j41(0,"i",49),e.nI1(1,"translate"),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG(),s=e.sdS(34);return o.rowToDelete=i,e.Njj(o.open(s))}),e.k0s()}2&n&&e.FS9("title",e.bMT(1,1,"device.byname.delete.colum"))}function B(n,r){if(1&n){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"div",50),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG();return e.Njj(o.copy(i))}),e.EFF(3,"\n "),e.j41(4,"div",51),e.EFF(5,"\n "),e.j41(6,"shared-custom-icon",52),e.nI1(7,"translate"),e.nI1(8,"translate"),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.bVm()}2&n&&(e.R7$(6),e.FS9("ngbPopover",e.bMT(7,2,"device.byname.optimized.popover.text.ok")),e.FS9("popoverTitle",e.bMT(8,4,"device.byname.optimized.popover.title.ok")))}function M(n,r){if(1&n){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"div",50),e.bIt("click",function(){e.eBV(t);const i=e.XpG().$implicit,o=e.XpG();return e.Njj(o.copy(i))}),e.EFF(3,"\n "),e.j41(4,"div",51),e.EFF(5,"\n "),e.j41(6,"shared-custom-icon",53),e.nI1(7,"translate"),e.nI1(8,"translate"),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.bVm()}2&n&&(e.R7$(6),e.FS9("ngbPopover",e.bMT(7,2,"device.byname.optimized.popover.text.ko")),e.FS9("popoverTitle",e.bMT(8,4,"device.byname.optimized.popover.title.ko")))}function $(n,r){if(1&n&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&n){const t=r.$implicit;e.R7$(),e.SpI("\n ",t,"\n ")}}function x(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",54),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG().$implicit;return e.DH7(o.ZDeviceName,i)||(o.ZDeviceName=i),e.Njj(i)}),e.bIt("input",function(){e.eBV(t);const i=e.XpG(2);return e.Njj(i.hasEditing=!0)}),e.k0s(),e.EFF(2,"\n ")}if(2&n){const t=e.XpG().$implicit;e.R7$(),e.R50("ngModel",t.ZDeviceName)}}function G(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",54),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG().$implicit;return e.DH7(o.ZDeviceName,i)||(o.ZDeviceName=i),e.Njj(i)}),e.bIt("input",function(){e.eBV(t);const i=e.XpG(2);return e.Njj(i.hasEditing=!0)}),e.k0s(),e.EFF(2,"\n ")}if(2&n){const t=e.XpG().$implicit;e.R7$(),e.R50("ngModel",t.ZDeviceName)}}function V(n,r){if(1&n&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&n){const t=r.$implicit;e.R7$(),e.SpI("\n ",t,"\n ")}}function P(n,r){if(1&n&&(e.EFF(0,"\n "),e.j41(1,"td"),e.EFF(2),e.k0s(),e.EFF(3,"\n ")),2&n){const t=e.XpG().$implicit;e.R7$(2),e.JRh(t.RSSI)}}function X(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td"),e.EFF(4,"\n "),e.DNE(5,S,1,2,"button",40),e.EFF(6,"\n "),e.DNE(7,w,2,3,"i",41),e.EFF(8,"\n "),e.k0s(),e.EFF(9,"\n "),e.j41(10,"td"),e.EFF(11,"\n "),e.DNE(12,B,13,6,"ng-container",42),e.EFF(13,"\n "),e.DNE(14,M,13,6,"ng-container",42),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n "),e.j41(17,"td"),e.EFF(18),e.k0s(),e.EFF(19,"\n "),e.j41(20,"td"),e.EFF(21),e.k0s(),e.EFF(22,"\n "),e.j41(23,"td"),e.EFF(24),e.k0s(),e.EFF(25,"\n "),e.j41(26,"td"),e.EFF(27,"\n "),e.DNE(28,$,2,1,"div",43),e.EFF(29,"\n "),e.k0s(),e.EFF(30,"\n "),e.j41(31,"td",44),e.EFF(32,"\n "),e.j41(33,"p-cellEditor"),e.EFF(34,"\n "),e.DNE(35,x,3,1,"ng-template",45),e.EFF(36,"\n "),e.DNE(37,G,3,1,"ng-template",46),e.EFF(38,"\n "),e.k0s(),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.j41(41,"td"),e.EFF(42,"\n "),e.DNE(43,V,2,1,"div",43),e.EFF(44,"\n "),e.k0s(),e.EFF(45,"\n "),e.j41(46,"td"),e.EFF(47),e.k0s(),e.EFF(48,"\n "),e.DNE(49,P,4,1),e.j41(50,"td"),e.EFF(51),e.k0s(),e.EFF(52,"\n "),e.j41(53,"td"),e.EFF(54),e.k0s(),e.EFF(55,"\n "),e.j41(56,"td"),e.EFF(57,"\n "),e.j41(58,"i",47),e.nI1(59,"translate"),e.nI1(60,"translate"),e.bIt("click",function(){const i=e.eBV(t).$implicit,o=e.XpG(),s=e.sdS(37);return o.rowParameter=i,e.Njj(o.editParameter(s))}),e.k0s(),e.EFF(61,"\n "),e.k0s(),e.EFF(62,"\n "),e.k0s(),e.EFF(63,"\n ")}if(2&n){const t=r.$implicit,a=e.XpG();e.R7$(5),e.Y8G("ngIf","{}"!==t.Param),e.R7$(2),e.Y8G("ngIf","not in DZ"===t.ConsistencyCheck||"Bad Pairing"===t.ConsistencyCheck||!t.WidgetList||0===t.WidgetList.length),e.R7$(5),e.Y8G("ngIf",t.CertifiedDevice),e.R7$(2),e.Y8G("ngIf",!t.CertifiedDevice),e.R7$(4),e.JRh(t._NwkId),e.R7$(3),e.JRh(t.IEEE),e.R7$(3),e.JRh(t.Model),e.R7$(4),e.Y8G("ngForOf",t.WidgetList),e.R7$(3),e.Y8G("pEditableColumn",t.ZDeviceName),e.R7$(12),e.Y8G("ngForOf",t.MacCapa),e.R7$(4),e.JRh(t.LQI),e.R7$(2),e.vxM(49,a.showRSSI?49:-1),e.R7$(2),e.JRh(t.Status),e.R7$(3),e.JRh(t.Health),e.R7$(4),e.xc7("color",t.CheckParam?"orange":"green"),e.FS9("ngbPopover",e.bMT(59,18,"device.byname.parameter.popover.text")),e.FS9("popoverTitle",e.bMT(60,20,"device.byname.parameter.popover.title"))}}function O(n,r){if(1&n&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td",55),e.EFF(4,"\n "),e.j41(5,"div",56),e.EFF(6,"\n "),e.j41(7,"div"),e.EFF(8,"\n "),e.j41(9,"strong"),e.EFF(10),e.nI1(11,"translate"),e.k0s(),e.EFF(12),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n "),e.k0s(),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n ")),2&n){const t=r.$implicit;e.R7$(10),e.SpI("",e.bMT(11,2,"device.byname.devicename.param")," : "),e.R7$(2),e.SpI(" ",t.Param,"\n ")}}function L(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",57),e.EFF(2,"\n "),e.nrm(3,"h4",58),e.EFF(4,"\n "),e.j41(5,"button",59),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",60),e.EFF(9,"\n "),e.j41(10,"div",61),e.EFF(11,"\n "),e.j41(12,"button",62),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("erase"))}),e.k0s(),e.EFF(13,"\n "),e.j41(14,"button",63),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("cancel"))}),e.k0s(),e.EFF(15,"\n "),e.k0s(),e.EFF(16,"\n")}}function Y(n,r){if(1&n){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",57),e.EFF(2,"\n "),e.nrm(3,"h4",64),e.EFF(4,"\n "),e.j41(5,"button",59),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("cancel"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.j41(8,"div",65),e.EFF(9,"\n "),e.nrm(10,"div",66),e.nI1(11,"translate"),e.EFF(12,"\n "),e.j41(13,"div",67),e.EFF(14,"\n "),e.j41(15,"input",68),e.bIt("click",function(){e.eBV(t);const i=e.XpG();return e.Njj(i.onChangeEnabled())}),e.k0s(),e.EFF(16,"\n "),e.nrm(17,"label",69),e.EFF(18,"\n "),e.k0s(),e.EFF(19,"\n "),e.j41(20,"div",70),e.EFF(21),e.nI1(22,"translate"),e.k0s(),e.EFF(23,"\n "),e.j41(24,"textarea",71),e.mxI("ngModelChange",function(i){e.eBV(t);const o=e.XpG();return e.DH7(o.parameter,i)||(o.parameter=i),e.Njj(i)}),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.j41(27,"div",61),e.EFF(28,"\n "),e.j41(29,"button",72),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.dismiss("cancel"))}),e.k0s(),e.EFF(30,"\n "),e.j41(31,"button",73),e.bIt("click",function(){const i=e.eBV(t).$implicit;return e.Njj(i.close("save"))}),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n")}if(2&n){const t=e.XpG();e.R7$(10),e.Y8G("innerHTML",e.bMT(11,4,"device.byname.parameter.alert.subject"),e.npT),e.R7$(5),e.Y8G("checked",t.enabled),e.R7$(6),e.SpI("",e.bMT(22,6,"device.byname.devicename.param")," :"),e.R7$(3),e.R50("ngModel",t.parameter)}}const b=new _.Vy("DeviceByNameComponent");let Z=(()=>{class n{apiService;translate;modalService;toastr;clipboard;devices;rows=[];hasEditing=!1;rowToDelete;rowParameter;parameter;expanded={};enabled=!1;prefixEnabled="Disabled";enabledTrue="'Disabled': 0";enabledFalse="'Disabled': 1";showRSSI=!1;constructor(t,a,i,o,s){this.apiService=t,this.translate=a,this.modalService=i,this.toastr=o,this.clipboard=s}ngOnChanges(t){t.devices.currentValue!==t.devices.previousValue&&(this.rows=this.devices,this.showRSSI=this.devices.filter(a=>a.RSSI).length>0)}open(t){this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then(()=>{this.delete()})}editParameter(t){this.parameter=this.rowParameter.Param,this.enabled=!this.parameter.includes(this.enabledFalse),this.enabled?(this.parameter=this.parameter.replace(this.enabledTrue.concat(","),""),this.parameter=this.parameter.replace(this.enabledTrue,"")):(this.parameter=this.parameter.replace(this.enabledFalse.concat(","),""),this.parameter=this.parameter.replace(this.enabledFalse,"")),this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then(()=>{this.parameter.includes(this.prefixEnabled)?this.toastr.error(this.translate.instant("device.byname.error.notify")):(this.parameter=this.parameter.replace("{",this.enabled?"{".concat(this.enabledTrue).concat(", "):"{".concat(this.enabledFalse).concat(", ")),this.updateValueJson(this.parameter,"Param",this.rowParameter._NwkId))})}onChangeEnabled(){this.enabled=!this.enabled}delete(){this.apiService.deleteZDeviceName(this.rowToDelete._NwkId).subscribe(()=>{const t=this.rows.indexOf(this.rowToDelete,0);this.rowToDelete=null,t>-1&&(this.rows.splice(t,1),this.rows=[...this.rows])})}updateValue(t,a,i){this.updateValueJson(t.target.value,a,i)}updateValueJson(t,a,i){this.hasEditing=!0;const o=this.rows.find(s=>s._NwkId===i);o?o[a]=t:b.error("row not found")}updateDevices(){this.apiService.putZDeviceName(this.rows).subscribe(t=>{b.debug(t),this.hasEditing=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}copy(t){this.apiService.getNonOptimizedDevice(t._NwkId).subscribe(a=>this.clipboard.copy(JSON.stringify(a)))}static \u0275fac=function(a){return new(a||n)(e.rXU(u.G),e.rXU(m.c$),e.rXU(v.Bq),e.rXU(h.tw),e.rXU(f.B0))};static \u0275cmp=e.VBU({type:n,selectors:[["app-device-by-name"]],inputs:{devices:"devices"},features:[e.OA$],decls:39,vars:26,consts:[["dt1",""],["content",""],["editContent",""],[1,"card"],[1,"card-header","fw-bold"],[1,"btn","btn-primary","float-end",3,"click","disabled","translate"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],["styleClass","p-datatable-sm","dataKey","_NwkId","responsiveLayout","scroll","stateStorage","local","stateKey","device",3,"globalFilterFields","rowHover","showCurrentPageReport","currentPageReportTemplate","rowsPerPageOptions","value","rows","paginator","scrollable"],["pTemplate","caption"],["pTemplate","header"],["pTemplate","body"],["pTemplate","rowexpansion"],[1,"flex"],[1,"p-input-icon-left","ml-auto"],[1,"pi","pi-search"],["pInputText","","type","text",3,"input","value","placeholder"],[2,"width","1rem"],["pSortableColumn","_NwkId",2,"width","7rem"],["field","_NwkId"],["pSortableColumn","IEEE",2,"width","5rem"],["field","IEEE"],["pSortableColumn","Model",2,"width","13rem"],["field","Model"],["pSortableColumn","WidgetList",2,"width","15rem"],["field","WidgetList"],["pSortableColumn","ZDeviceName",2,"width","20rem"],["field","ZDeviceName"],["pSortableColumn","MacCapa",2,"width","10rem"],["field","MacCapa"],["pSortableColumn","LQI",2,"width","5rem"],["field","LQI"],["pSortableColumn","Status",2,"width","7rem"],["field","Status"],["pSortableColumn","Health",2,"width","6rem"],["field","Health"],[2,"width","2rem"],["pSortableColumn","RSSI",2,"width","5rem"],["field","RSSI"],["type","button","pButton","","pRipple","","class","p-button-text p-button-rounded p-button-plain",3,"pRowToggler","icon",4,"ngIf"],["class","fa fa-trash","style","cursor: pointer",3,"title","click",4,"ngIf"],[4,"ngIf"],[4,"ngFor","ngForOf"],["pEditableColumnField","ZDeviceName",3,"pEditableColumn"],["pTemplate","input"],["pTemplate","output"],["triggers","mouseenter:mouseleave",1,"fas","fa-cog",2,"cursor","pointer",3,"click","ngbPopover","popoverTitle"],["type","button","pButton","","pRipple","",1,"p-button-text","p-button-rounded","p-button-plain",3,"pRowToggler","icon"],[1,"fa","fa-trash",2,"cursor","pointer",3,"click","title"],[3,"click"],[1,"container"],["triggers","mouseenter:mouseleave","iconName","CHECK_ICON",1,"container__icon","container__icon--green",3,"ngbPopover","popoverTitle"],["triggers","mouseenter:mouseleave","iconName","X_ICON",1,"container__icon","container__icon--orange",3,"ngbPopover","popoverTitle"],["pInputText","","type","text",3,"ngModelChange","input","ngModel"],["colspan","12"],[2,"padding-left","35px"],[1,"modal-header"],["id","modal-basic-title","translate","device.byname.alert.title",1,"modal-title"],["type","button","aria-label","Close",1,"btn-close",3,"click"],["translate","device.byname.alert.subject",1,"modal-body"],[1,"modal-footer"],["type","button","translate","device.byname.alert.delete",1,"btn","btn-primary",3,"click"],["type","button","translate","device.byname.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","device.byname.parameter.alert.title",1,"modal-title"],[1,"modal-body"],[3,"innerHTML"],[1,"switch","switch-sm","mt-3","me-2","pe-3"],["type","checkbox","id","switch-enabled",3,"click","checked"],["for","switch-enabled","translate","device.byname.devicename.enabled",1,"mb-0"],[1,"mt-3"],["name","parameter","rows","5",3,"ngModelChange","ngModel"],["type","button","translate","device.byname.parameter.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["type","button","translate","device.byname.parameter.alert.save",1,"btn","btn-primary",3,"click"]],template:function(a,i){if(1&a){const o=e.RV6();e.j41(0,"div",3),e.EFF(1,"\n "),e.j41(2,"div",4),e.EFF(3),e.nI1(4,"translate"),e.j41(5,"button",5),e.nI1(6,"translate"),e.bIt("click",function(){return e.eBV(o),e.Njj(i.updateDevices())}),e.k0s(),e.EFF(7,"\n "),e.k0s(),e.EFF(8,"\n "),e.j41(9,"div",6),e.EFF(10,"\n "),e.nrm(11,"p",7),e.nI1(12,"translate"),e.nI1(13,"translate"),e.EFF(14,"\n "),e.j41(15,"div",8),e.EFF(16,"\n "),e.j41(17,"p-table",9,0),e.nI1(19,"translate"),e.EFF(20,"\n "),e.DNE(21,N,12,4,"ng-template",10),e.EFF(22,"\n "),e.DNE(23,R,71,37,"ng-template",11),e.EFF(24,"\n "),e.DNE(25,X,64,22,"ng-template",12),e.EFF(26,"\n "),e.DNE(27,O,17,4,"ng-template",13),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.k0s(),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n"),e.k0s(),e.EFF(32,"\n\n"),e.DNE(33,L,17,0,"ng-template",null,1,e.C5r),e.EFF(35,"\n\n"),e.DNE(36,Y,34,8,"ng-template",null,2,e.C5r),e.EFF(38,"\n")}2&a&&(e.R7$(3),e.SpI("\n ",e.bMT(4,14,"device.byname.header"),"\n "),e.R7$(2),e.FS9("translate",e.bMT(6,16,"device.byname.validate.button")),e.Y8G("disabled",!i.hasEditing),e.R7$(6),e.Y8G("innerHTML",e.bMT(12,18,"group.create.subtitle"),e.npT)("innerHTML",e.bMT(13,20,"device.byname.subtitle"),e.npT),e.R7$(6),e.FS9("currentPageReportTemplate",e.bMT(19,22,"TOTAL")),e.Y8G("globalFilterFields",e.lJ4(24,C))("rowHover",!0)("showCurrentPageReport",!0)("rowsPerPageOptions",e.lJ4(25,T))("value",i.rows)("rows",10)("paginator",!0)("scrollable",!0))},dependencies:[E.Sq,E.bT,l.me,l.BC,l.vS,v.ZM,m.Mm,p.XI,y.Ei,p.Tg,p.FP,p.hp,p.c5,p.yc,k.S,I._f,j,m.D9],styles:[".container[_ngcontent-%COMP%]{display:flex}.container--green[_ngcontent-%COMP%]{color:green}.container--primary-color[_ngcontent-%COMP%]{color:var(--primary-color)}.container__icon[_ngcontent-%COMP%]{flex:1}.container__icon--orange[_ngcontent-%COMP%]{color:orange}.container__icon--green[_ngcontent-%COMP%]{color:green}textarea[_ngcontent-%COMP%]{width:100%}"]})}return n})();const H=[{path:"",component:(()=>{class n{apiService;formBuilder;translate;form;devices;constructor(t,a,i){this.apiService=t,this.formBuilder=a,this.translate=i}ngOnInit(){this.form=this.formBuilder.group({devices:this.formBuilder.group({}),permit:this.formBuilder.group({})}),this.apiService.getZDeviceName().subscribe(t=>{this.devices=t})}static \u0275fac=function(a){return new(a||n)(e.rXU(u.G),e.rXU(l.ok),e.rXU(m.c$))};static \u0275cmp=e.VBU({type:n,selectors:[["app-device"]],decls:5,vars:2,consts:[[3,"formGroup"],[3,"devices"]],template:function(a,i){1&a&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.nrm(2,"app-device-by-name",1),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n")),2&a&&(e.Y8G("formGroup",i.form),e.R7$(2),e.Y8G("devices",i.devices))},dependencies:[l.qT,l.cb,l.j4,Z]})}return n})(),data:{title:(0,_.o6)("device")}}];let J=(()=>{class n{static \u0275fac=function(a){return new(a||n)};static \u0275mod=e.$C({type:n});static \u0275inj=e.G2t({imports:[d.iI.forChild(H),d.iI]})}return n})(),U=(()=>{class n{static \u0275fac=function(a){return new(a||n)};static \u0275mod=e.$C({type:n});static \u0275inj=e.G2t({imports:[J,g.G,l.YN]})}return n})()}}]); \ No newline at end of file diff --git a/www/z4d/846.e10721e2f1184a6d.js b/www/z4d/846.273fca847945652d.js similarity index 82% rename from www/z4d/846.e10721e2f1184a6d.js rename to www/z4d/846.273fca847945652d.js index e68b14700..fd3c496f4 100644 --- a/www/z4d/846.e10721e2f1184a6d.js +++ b/www/z4d/846.273fca847945652d.js @@ -1 +1 @@ -(self.webpackChunkz4d_plugin=self.webpackChunkz4d_plugin||[]).push([[846],{2846:(W,Y,m)=>{"use strict";m.r(Y),m.d(Y,{ToolsModule:()=>ln});var q=m(93887),e=m(54438),h=m(60177);const R=["dialogPopup"],H=["hueSlider"],P=["alphaSlider"];function y(i,l){if(1&i&&e.nrm(0,"div"),2&i){const t=e.XpG();e.ZvI("arrow arrow-",t.cpUsePosition,""),e.xc7("left",t.cpArrowPosition)("top",t.arrowTop,"px")}}function z(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",28),e.bIt("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onColorChange(n))})("dragStart",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onDragStart("saturation-lightness"))})("dragEnd",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onDragEnd("saturation-lightness"))}),e.nrm(1,"div",16),e.k0s()}if(2&i){const t=e.XpG();e.xc7("background-color",t.hueSliderColor),e.Y8G("rgX",1)("rgY",1),e.R7$(),e.xc7("top",null==t.slider?null:t.slider.v,"px")("left",null==t.slider?null:t.slider.s,"px")}}function M(i,l){1&i&&(e.qSk(),e.j41(0,"svg",29),e.nrm(1,"path",30)(2,"path",31),e.k0s())}function u(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",32),e.bIt("click",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAddPresetColor(n,r.selectedColor))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG();e.HbH(t.cpAddColorButtonClass),e.Y8G("disabled",t.cpPresetColors&&t.cpPresetColors.length>=t.cpMaxPresetColorsLength),e.R7$(),e.SpI(" ",t.cpAddColorButtonText," ")}}function g(i,l){1&i&&e.nrm(0,"div",33)}function x(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.cmykText?null:t.cmykText.a)}}function f(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function b(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",34)(1,"div",35)(2,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onCyanInput(n))}),e.k0s(),e.j41(3,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onMagentaInput(n))}),e.k0s(),e.j41(4,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onYellowInput(n))}),e.k0s(),e.j41(5,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onBlackInput(n))}),e.k0s(),e.DNE(6,x,1,2,"input",37),e.k0s(),e.j41(7,"div",35)(8,"div"),e.EFF(9,"C"),e.k0s(),e.j41(10,"div"),e.EFF(11,"M"),e.k0s(),e.j41(12,"div"),e.EFF(13,"Y"),e.k0s(),e.j41(14,"div"),e.EFF(15,"K"),e.k0s(),e.DNE(16,f,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",3!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.c),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.m),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.y),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.k),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(10),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function Z(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.hslaText?null:t.hslaText.a)}}function U(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function G(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",40)(1,"div",35)(2,"input",41),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onHueInput(n))}),e.k0s(),e.j41(3,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onSaturationInput(n))}),e.k0s(),e.j41(4,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onLightnessInput(n))}),e.k0s(),e.DNE(5,Z,1,2,"input",37),e.k0s(),e.j41(6,"div",35)(7,"div"),e.EFF(8,"H"),e.k0s(),e.j41(9,"div"),e.EFF(10,"S"),e.k0s(),e.j41(11,"div"),e.EFF(12,"L"),e.k0s(),e.DNE(13,U,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",2!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",360)("value",null==t.hslaText?null:t.hslaText.h),e.R7$(),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.s),e.R7$(),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.l),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(8),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function K(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.rgbaText?null:t.rgbaText.a)}}function N(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function S(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",42)(1,"div",35)(2,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onRedInput(n))}),e.k0s(),e.j41(3,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onGreenInput(n))}),e.k0s(),e.j41(4,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onBlueInput(n))}),e.k0s(),e.DNE(5,K,1,2,"input",37),e.k0s(),e.j41(6,"div",35)(7,"div"),e.EFF(8,"R"),e.k0s(),e.j41(9,"div"),e.EFF(10,"G"),e.k0s(),e.j41(11,"div"),e.EFF(12,"B"),e.k0s(),e.DNE(13,N,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",1!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.r),e.R7$(),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.g),e.R7$(),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.b),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(8),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function de(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",t.hexAlpha)}}function ue(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function ge(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",44)(1,"div",35)(2,"input",45),e.bIt("blur",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onHexInput(null))})("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onHexInput(n))}),e.k0s(),e.DNE(3,de,1,2,"input",37),e.k0s(),e.j41(4,"div",35)(5,"div"),e.EFF(6,"Hex"),e.k0s(),e.DNE(7,ue,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",0!==t.format?"none":"block"),e.AVh("hex-alpha","forced"===t.cpAlphaChannel),e.R7$(2),e.Y8G("value",t.hexText),e.R7$(),e.Y8G("ngIf","forced"===t.cpAlphaChannel),e.R7$(4),e.Y8G("ngIf","forced"===t.cpAlphaChannel)}}function me(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.hslaText?null:t.hslaText.a)}}function he(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",46)(1,"div",35)(2,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onValueInput(n))}),e.k0s(),e.DNE(3,me,1,2,"input",37),e.k0s(),e.j41(4,"div",35)(5,"div"),e.EFF(6,"V"),e.k0s(),e.j41(7,"div"),e.EFF(8,"A"),e.k0s()()()}if(2&i){const t=e.XpG();e.R7$(2),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.l),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function fe(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",47)(1,"span",48),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onFormatToggle(-1))}),e.k0s(),e.j41(2,"span",48),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onFormatToggle(1))}),e.k0s()()}}function ve(i,l){if(1&i){const t=e.RV6();e.j41(0,"span",55),e.bIt("click",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG(3);return e.Njj(s.onRemovePresetColor(n,r))}),e.k0s()}if(2&i){const t=e.XpG(4);e.HbH(t.cpRemoveColorButtonClass)}}function Ce(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",53),e.bIt("click",function(){const n=e.eBV(t).$implicit,r=e.XpG(3);return e.Njj(r.setColorFromString(n))}),e.DNE(1,ve,1,3,"span",54),e.k0s()}if(2&i){const t=l.$implicit,o=e.XpG(3);e.xc7("background-color",t),e.R7$(),e.Y8G("ngIf",o.cpAddColorButton)}}function Fe(i,l){if(1&i&&(e.j41(0,"div"),e.DNE(1,Ce,2,3,"div",52),e.k0s()),2&i){const t=e.XpG(2);e.HbH(t.cpPresetColorsClass),e.R7$(),e.Y8G("ngForOf",t.cpPresetColors)}}function _e(i,l){if(1&i&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&i){const t=e.XpG(2);e.HbH(t.cpPresetEmptyMessageClass),e.R7$(),e.JRh(t.cpPresetEmptyMessage)}}function be(i,l){if(1&i&&(e.j41(0,"div",49),e.nrm(1,"hr"),e.j41(2,"div",50),e.EFF(3),e.k0s(),e.DNE(4,Fe,2,4,"div",51)(5,_e,2,4,"div",51),e.k0s()),2&i){const t=e.XpG();e.R7$(3),e.JRh(t.cpPresetLabel),e.R7$(),e.Y8G("ngIf",null==t.cpPresetColors?null:t.cpPresetColors.length),e.R7$(),e.Y8G("ngIf",!(null!=t.cpPresetColors&&t.cpPresetColors.length)&&t.cpAddColorButton)}}function ke(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",58),e.bIt("click",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onCancelColor(n))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG(2);e.HbH(t.cpCancelButtonClass),e.R7$(),e.JRh(t.cpCancelButtonText)}}function Ee(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",58),e.bIt("click",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG(2);e.HbH(t.cpOKButtonClass),e.R7$(),e.JRh(t.cpOKButtonText)}}function ye(i,l){if(1&i&&(e.j41(0,"div",56),e.DNE(1,ke,2,4,"button",57)(2,Ee,2,4,"button",57),e.k0s()),2&i){const t=e.XpG();e.R7$(),e.Y8G("ngIf",t.cpCancelButton),e.R7$(),e.Y8G("ngIf",t.cpOKButton)}}function xe(i,l){1&i&&e.eu8(0)}function we(i,l){if(1&i&&(e.j41(0,"div",59),e.DNE(1,xe,1,0,"ng-container",60),e.k0s()),2&i){const t=e.XpG();e.R7$(),e.Y8G("ngTemplateOutlet",t.cpExtraTemplate)}}var k=function(i){return i[i.HEX=0]="HEX",i[i.RGBA=1]="RGBA",i[i.HSLA=2]="HSLA",i[i.CMYK=3]="CMYK",i}(k||{});class j{r;g;b;a;constructor(l,t,o,n){this.r=l,this.g=t,this.b=o,this.a=n}}class L{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}class B{h;s;l;a;constructor(l,t,o,n){this.h=l,this.s=t,this.l=o,this.a=n}}class O{c;m;y;k;a;constructor(l,t,o,n,r=1){this.c=l,this.m=t,this.y=o,this.k=n,this.a=r}}let Te=(()=>{class i{rg;text;newValue=new e.bkB;inputChange(t){const o=t.target.value;if(void 0===this.rg)this.newValue.emit(o);else{const n=parseFloat(o);this.newValue.emit({v:n,rg:this.rg})}}static \u0275fac=function(o){return new(o||i)};static \u0275dir=e.FsC({type:i,selectors:[["","text",""]],hostBindings:function(o,n){1&o&&e.bIt("input",function(s){return n.inputChange(s)})},inputs:{rg:"rg",text:"text"},outputs:{newValue:"newValue"}})}return i})(),Ie=(()=>{class i{elRef;listenerMove;listenerStop;rgX;rgY;slider;dragEnd=new e.bkB;dragStart=new e.bkB;newValue=new e.bkB;mouseDown(t){this.start(t)}touchStart(t){this.start(t)}constructor(t){this.elRef=t,this.listenerMove=o=>this.move(o),this.listenerStop=()=>this.stop()}move(t){t.preventDefault(),this.setCursor(t)}start(t){this.setCursor(t),t.stopPropagation(),document.addEventListener("mouseup",this.listenerStop),document.addEventListener("touchend",this.listenerStop),document.addEventListener("mousemove",this.listenerMove),document.addEventListener("touchmove",this.listenerMove),this.dragStart.emit()}stop(){document.removeEventListener("mouseup",this.listenerStop),document.removeEventListener("touchend",this.listenerStop),document.removeEventListener("mousemove",this.listenerMove),document.removeEventListener("touchmove",this.listenerMove),this.dragEnd.emit()}getX(t){const o=this.elRef.nativeElement.getBoundingClientRect();return(void 0!==t.pageX?t.pageX:t.touches[0].pageX)-o.left-window.pageXOffset}getY(t){const o=this.elRef.nativeElement.getBoundingClientRect();return(void 0!==t.pageY?t.pageY:t.touches[0].pageY)-o.top-window.pageYOffset}setCursor(t){const o=this.elRef.nativeElement.offsetWidth,n=this.elRef.nativeElement.offsetHeight,r=Math.max(0,Math.min(this.getX(t),o)),s=Math.max(0,Math.min(this.getY(t),n));void 0!==this.rgX&&void 0!==this.rgY?this.newValue.emit({s:r/o,v:1-s/n,rgX:this.rgX,rgY:this.rgY}):void 0===this.rgX&&void 0!==this.rgY?this.newValue.emit({v:s/n,rgY:this.rgY}):void 0!==this.rgX&&void 0===this.rgY&&this.newValue.emit({v:r/o,rgX:this.rgX})}static \u0275fac=function(o){return new(o||i)(e.rXU(e.aKT))};static \u0275dir=e.FsC({type:i,selectors:[["","slider",""]],hostBindings:function(o,n){1&o&&e.bIt("mousedown",function(s){return n.mouseDown(s)})("touchstart",function(s){return n.touchStart(s)})},inputs:{rgX:"rgX",rgY:"rgY",slider:"slider"},outputs:{dragEnd:"dragEnd",dragStart:"dragStart",newValue:"newValue"}})}return i})();class ne{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}class oe{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}let J=(()=>{class i{active=null;setActive(t){this.active&&this.active!==t&&"inline"!==this.active.cpDialogDisplay&&this.active.closeDialog(),this.active=t}hsva2hsla(t){const o=t.h,n=t.s,r=t.v,s=t.a;if(0===r)return new B(o,0,0,s);if(0===n&&1===r)return new B(o,1,1,s);{const a=r*(2-n)/2;return new B(o,r*n/(1-Math.abs(2*a-1)),a,s)}}hsla2hsva(t){const o=Math.min(t.h,1),n=Math.min(t.s,1),r=Math.min(t.l,1),s=Math.min(t.a,1);if(0===r)return new L(o,0,0,s);{const a=r+n*(1-Math.abs(2*r-1))/2;return new L(o,2*(a-r)/a,a,s)}}hsvaToRgba(t){let o,n,r;const s=t.h,a=t.s,d=t.v,p=t.a,F=Math.floor(6*s),_=6*s-F,C=d*(1-a),E=d*(1-_*a),w=d*(1-(1-_)*a);switch(F%6){case 0:o=d,n=w,r=C;break;case 1:o=E,n=d,r=C;break;case 2:o=C,n=d,r=w;break;case 3:o=C,n=E,r=d;break;case 4:o=w,n=C,r=d;break;case 5:o=d,n=C,r=E;break;default:o=0,n=0,r=0}return new j(o,n,r,p)}cmykToRgb(t){return new j((1-t.c)*(1-t.k),(1-t.m)*(1-t.k),(1-t.y)*(1-t.k),t.a)}rgbaToCmyk(t){const o=1-Math.max(t.r,t.g,t.b);return 1===o?new O(0,0,0,1,t.a):new O((1-t.r-o)/(1-o),(1-t.g-o)/(1-o),(1-t.b-o)/(1-o),o,t.a)}rgbaToHsva(t){let o,n;const r=Math.min(t.r,1),s=Math.min(t.g,1),a=Math.min(t.b,1),d=Math.min(t.a,1),p=Math.max(r,s,a),F=Math.min(r,s,a),_=p,C=p-F;if(n=0===p?0:C/p,p===F)o=0;else{switch(p){case r:o=(s-a)/C+(s{class i{ngZone;elRef;cdRef;document;platformId;service;isIE10=!1;cmyk;hsva;width;height;cmykColor;outputColor;initialColor;fallbackColor;listenerResize;listenerMouseDown;directiveInstance;sliderH;sliderDimMax;directiveElementRef;dialogArrowSize=10;dialogArrowOffset=15;dialogInputFields=[k.HEX,k.RGBA,k.HSLA,k.CMYK];useRootViewContainer=!1;show;hidden;top;left;position;format;slider;hexText;hexAlpha;cmykText;hslaText;rgbaText;arrowTop;selectedColor;hueSliderColor;alphaSliderColor;cpWidth;cpHeight;cpColorMode;cpCmykEnabled;cpAlphaChannel;cpOutputFormat;cpDisableInput;cpDialogDisplay;cpIgnoredElements;cpSaveClickOutside;cpCloseClickOutside;cpPosition;cpUsePosition;cpPositionOffset;cpOKButton;cpOKButtonText;cpOKButtonClass;cpCancelButton;cpCancelButtonText;cpCancelButtonClass;cpEyeDropper;eyeDropperSupported;cpPresetLabel;cpPresetColors;cpPresetColorsClass;cpMaxPresetColorsLength;cpPresetEmptyMessage;cpPresetEmptyMessageClass;cpAddColorButton;cpAddColorButtonText;cpAddColorButtonClass;cpRemoveColorButtonClass;cpArrowPosition;cpTriggerElement;cpExtraTemplate;dialogElement;hueSlider;alphaSlider;handleEsc(t){this.show&&"popup"===this.cpDialogDisplay&&this.onCancelColor(t)}handleEnter(t){this.show&&"popup"===this.cpDialogDisplay&&this.onAcceptColor(t)}constructor(t,o,n,r,s,a){this.ngZone=t,this.elRef=o,this.cdRef=n,this.document=r,this.platformId=s,this.service=a,this.eyeDropperSupported=(0,h.UE)(this.platformId)&&"EyeDropper"in this.document.defaultView}ngOnInit(){this.slider=new ne(0,0,0,0),this.sliderDimMax=new oe(this.hueSlider.nativeElement.offsetWidth||140,this.cpWidth,130,this.alphaSlider.nativeElement.offsetWidth||140),this.format=this.cpCmykEnabled?k.CMYK:"rgba"===this.cpOutputFormat?k.RGBA:"hsla"===this.cpOutputFormat?k.HSLA:k.HEX,this.listenerMouseDown=n=>{this.onMouseDown(n)},this.listenerResize=()=>{this.onResize()},this.openDialog(this.initialColor,!1)}ngOnDestroy(){this.closeDialog()}ngAfterViewInit(){230===this.cpWidth&&"inline"!==this.cpDialogDisplay||(this.sliderDimMax=new oe(this.hueSlider.nativeElement.offsetWidth||140,this.cpWidth,130,this.alphaSlider.nativeElement.offsetWidth||140),this.updateColorPicker(!1),this.cdRef.detectChanges())}openDialog(t,o=!0){this.service.setActive(this),this.width||(this.cpWidth=this.directiveElementRef.nativeElement.offsetWidth),this.height||(this.height=320),this.setInitialColor(t),this.setColorFromString(t,o),this.openColorPicker()}closeDialog(){this.closeColorPicker()}setupDialog(t,o,n,r,s,a,d,p,F,_,C,E,w,te,X,T,an,cn,pn,dn,un,gn,mn,hn,fn,vn,Cn,Fn,_n,bn,kn,En,yn,xn,wn,jn,An,Tn){this.setInitialColor(n),this.setColorMode(p),this.isIE10=10===function Ae(){let i="";typeof navigator<"u"&&(i=navigator.userAgent.toLowerCase());const l=i.indexOf("msie ");return l>0&&parseInt(i.substring(l+5,i.indexOf(".",l)),10)}(),this.directiveInstance=t,this.directiveElementRef=o,this.cpDisableInput=E,this.cpCmykEnabled=F,this.cpAlphaChannel=_,this.cpOutputFormat=C,this.cpDialogDisplay=a,this.cpIgnoredElements=w,this.cpSaveClickOutside=te,this.cpCloseClickOutside=X,this.useRootViewContainer=T,this.width=this.cpWidth=parseInt(r,10),this.height=this.cpHeight=parseInt(s,10),this.cpPosition=an,this.cpPositionOffset=parseInt(cn,10),this.cpOKButton=vn,this.cpOKButtonText=Fn,this.cpOKButtonClass=Cn,this.cpCancelButton=_n,this.cpCancelButtonText=kn,this.cpCancelButtonClass=bn,this.cpEyeDropper=jn,this.fallbackColor=d||"#fff",this.setPresetConfig(dn,un),this.cpPresetColorsClass=gn,this.cpMaxPresetColorsLength=mn,this.cpPresetEmptyMessage=hn,this.cpPresetEmptyMessageClass=fn,this.cpAddColorButton=En,this.cpAddColorButtonText=xn,this.cpAddColorButtonClass=yn,this.cpRemoveColorButtonClass=wn,this.cpTriggerElement=An,this.cpExtraTemplate=Tn,pn||(this.dialogArrowOffset=0),"inline"===a&&(this.dialogArrowSize=0,this.dialogArrowOffset=0),"hex"===C&&"always"!==_&&"forced"!==_&&(this.cpAlphaChannel="disabled")}setColorMode(t){switch(t.toString().toUpperCase()){case"1":case"C":case"COLOR":default:this.cpColorMode=1;break;case"2":case"G":case"GRAYSCALE":this.cpColorMode=2;break;case"3":case"P":case"PRESETS":this.cpColorMode=3}}setInitialColor(t){this.initialColor=t}setPresetConfig(t,o){this.cpPresetLabel=t,this.cpPresetColors=o}setColorFromString(t,o=!0,n=!0){let r;"always"===this.cpAlphaChannel||"forced"===this.cpAlphaChannel?(r=this.service.stringToHsva(t,!0),!r&&!this.hsva&&(r=this.service.stringToHsva(t,!1))):r=this.service.stringToHsva(t,!1),!r&&!this.hsva&&(r=this.service.stringToHsva(this.fallbackColor,!1)),r&&(this.hsva=r,this.sliderH=this.hsva.h,"hex"===this.cpOutputFormat&&"disabled"===this.cpAlphaChannel&&(this.hsva.a=1),this.updateColorPicker(o,n))}onResize(){"fixed"===this.position?this.setDialogPosition():"inline"!==this.cpDialogDisplay&&this.closeColorPicker()}onDragEnd(t){this.directiveInstance.sliderDragEnd({slider:t,color:this.outputColor})}onDragStart(t){this.directiveInstance.sliderDragStart({slider:t,color:this.outputColor})}onMouseDown(t){this.show&&!this.isIE10&&"popup"===this.cpDialogDisplay&&t.target!==this.directiveElementRef.nativeElement&&!this.isDescendant(this.elRef.nativeElement,t.target)&&!this.isDescendant(this.directiveElementRef.nativeElement,t.target)&&0===this.cpIgnoredElements.filter(o=>o===t.target).length&&this.ngZone.run(()=>{this.cpSaveClickOutside?this.directiveInstance.colorSelected(this.outputColor):(this.hsva=null,this.setColorFromString(this.initialColor,!1),this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.initialColor),this.directiveInstance.colorCanceled()),this.cpCloseClickOutside&&this.closeColorPicker()})}onAcceptColor(t){t.stopPropagation(),this.outputColor&&this.directiveInstance.colorSelected(this.outputColor),"popup"===this.cpDialogDisplay&&this.closeColorPicker()}onCancelColor(t){this.hsva=null,t.stopPropagation(),this.directiveInstance.colorCanceled(),this.setColorFromString(this.initialColor,!0),"popup"===this.cpDialogDisplay&&(this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.initialColor,!0),this.closeColorPicker())}onEyeDropper(){this.eyeDropperSupported&&(new window.EyeDropper).open().then(o=>{this.setColorFromString(o.sRGBHex,!0)})}onFormatToggle(t){const o=this.dialogInputFields.length-(this.cpCmykEnabled?0:1),n=((this.dialogInputFields.indexOf(this.format)+t)%o+o)%o;this.format=this.dialogInputFields[n]}onColorChange(t){this.hsva.s=t.s/t.rgX,this.hsva.v=t.v/t.rgY,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"lightness",value:this.hsva.v,color:this.outputColor}),this.directiveInstance.sliderChanged({slider:"saturation",value:this.hsva.s,color:this.outputColor})}onHueChange(t){this.hsva.h=t.v/t.rgX,this.sliderH=this.hsva.h,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"hue",value:this.hsva.h,color:this.outputColor})}onValueChange(t){this.hsva.v=t.v/t.rgX,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"value",value:this.hsva.v,color:this.outputColor})}onAlphaChange(t){this.hsva.a=t.v/t.rgX,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"alpha",value:this.hsva.a,color:this.outputColor})}onHexInput(t){if(null===t)this.updateColorPicker();else{t&&"#"!==t[0]&&(t="#"+t);let o=/^#([a-f0-9]{3}|[a-f0-9]{6})$/gi;"always"===this.cpAlphaChannel&&(o=/^#([a-f0-9]{3}|[a-f0-9]{6}|[a-f0-9]{8})$/gi);const n=o.test(t);n&&(t.length<5&&(t="#"+t.substring(1).split("").map(r=>r+r).join("")),"forced"===this.cpAlphaChannel&&(t+=Math.round(255*this.hsva.a).toString(16)),this.setColorFromString(t,!0,!1)),this.directiveInstance.inputChanged({input:"hex",valid:n,value:t,color:this.outputColor})}}onRedInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.r=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"red",valid:n,value:o.r,color:this.outputColor})}onBlueInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.b=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"blue",valid:n,value:o.b,color:this.outputColor})}onGreenInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.g=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"green",valid:n,value:o.g,color:this.outputColor})}onHueInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.h=t.v/t.rg,this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"hue",valid:o,value:this.hsva.h,color:this.outputColor})}onValueInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.v=t.v/t.rg,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"value",valid:o,value:this.hsva.v,color:this.outputColor})}onAlphaInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.a=t.v/t.rg,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"alpha",valid:o,value:this.hsva.a,color:this.outputColor})}onLightnessInput(t){const o=this.service.hsva2hsla(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.l=t.v/t.rg,this.hsva=this.service.hsla2hsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"lightness",valid:n,value:o.l,color:this.outputColor})}onSaturationInput(t){const o=this.service.hsva2hsla(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.s=t.v/t.rg,this.hsva=this.service.hsla2hsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"saturation",valid:n,value:o.s,color:this.outputColor})}onCyanInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.c=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"cyan",valid:!0,value:this.cmyk.c,color:this.outputColor})}onMagentaInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.m=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"magenta",valid:!0,value:this.cmyk.m,color:this.outputColor})}onYellowInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.y=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"yellow",valid:!0,value:this.cmyk.y,color:this.outputColor})}onBlackInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.k=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"black",valid:!0,value:this.cmyk.k,color:this.outputColor})}onAddPresetColor(t,o){t.stopPropagation(),this.cpPresetColors.filter(n=>n===o).length||(this.cpPresetColors=this.cpPresetColors.concat(o),this.directiveInstance.presetColorsChanged(this.cpPresetColors))}onRemovePresetColor(t,o){t.stopPropagation(),this.cpPresetColors=this.cpPresetColors.filter(n=>n!==o),this.directiveInstance.presetColorsChanged(this.cpPresetColors)}openColorPicker(){this.show||(this.show=!0,this.hidden=!0,setTimeout(()=>{this.hidden=!1,this.setDialogPosition(),this.cdRef.detectChanges()},0),this.directiveInstance.stateChanged(!0),this.isIE10||this.ngZone.runOutsideAngular(()=>{ie?document.addEventListener("touchstart",this.listenerMouseDown):document.addEventListener("mousedown",this.listenerMouseDown)}),window.addEventListener("resize",this.listenerResize))}closeColorPicker(){this.show&&(this.show=!1,this.directiveInstance.stateChanged(!1),this.isIE10||(ie?document.removeEventListener("touchstart",this.listenerMouseDown):document.removeEventListener("mousedown",this.listenerMouseDown)),window.removeEventListener("resize",this.listenerResize),this.cdRef.destroyed||this.cdRef.detectChanges())}updateColorPicker(t=!0,o=!0,n=!1){if(this.sliderDimMax){let r,s,a;2===this.cpColorMode&&(this.hsva.s=0);const d=this.outputColor;if(s=this.service.hsva2hsla(this.hsva),this.cpCmykEnabled?(n?(a=this.service.cmykToRgb(this.service.normalizeCMYK(this.cmyk)),this.hsva=this.service.rgbaToHsva(a)):(a=this.service.hsvaToRgba(this.hsva),this.cmyk=this.service.denormalizeCMYK(this.service.rgbaToCmyk(a))),a=this.service.denormalizeRGBA(a),this.sliderH=this.hsva.h):a=this.service.denormalizeRGBA(this.service.hsvaToRgba(this.hsva)),r=this.service.denormalizeRGBA(this.service.hsvaToRgba(new L(this.sliderH||this.hsva.h,1,1,1))),o&&(this.hslaText=new B(Math.round(360*s.h),Math.round(100*s.s),Math.round(100*s.l),Math.round(100*s.a)/100),this.rgbaText=new j(a.r,a.g,a.b,Math.round(100*a.a)/100),this.cpCmykEnabled&&(this.cmykText=new O(this.cmyk.c,this.cmyk.m,this.cmyk.y,this.cmyk.k,Math.round(100*this.cmyk.a)/100)),this.hexText=this.service.rgbaToHex(a,"always"===this.cpAlphaChannel),this.hexAlpha=this.rgbaText.a),"auto"===this.cpOutputFormat&&this.format!==k.RGBA&&this.format!==k.CMYK&&this.format!==k.HSLA&&this.hsva.a<1&&(this.format=this.hsva.a<1?k.RGBA:k.HEX),this.hueSliderColor="rgb("+r.r+","+r.g+","+r.b+")",this.alphaSliderColor="rgb("+a.r+","+a.g+","+a.b+")",this.outputColor=this.service.outputFormat(this.hsva,this.cpOutputFormat,this.cpAlphaChannel),this.selectedColor=this.service.outputFormat(this.hsva,"rgba",null),this.format!==k.CMYK)this.cmykColor="";else if("always"===this.cpAlphaChannel||"enabled"===this.cpAlphaChannel||"forced"===this.cpAlphaChannel){const p=Math.round(100*this.cmyk.a)/100;this.cmykColor=`cmyka(${this.cmyk.c},${this.cmyk.m},${this.cmyk.y},${this.cmyk.k},${p})`}else this.cmykColor=`cmyk(${this.cmyk.c},${this.cmyk.m},${this.cmyk.y},${this.cmyk.k})`;this.slider=new ne((this.sliderH||this.hsva.h)*this.sliderDimMax.h-8,this.hsva.s*this.sliderDimMax.s-8,(1-this.hsva.v)*this.sliderDimMax.v-8,this.hsva.a*this.sliderDimMax.a-8),t&&d!==this.outputColor&&(this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.outputColor))}}setDialogPosition(){if("inline"===this.cpDialogDisplay)this.position="relative";else{let n,t="static",o="",r=null,s=null,a=this.directiveElementRef.nativeElement.parentNode;const d=this.dialogElement.nativeElement.offsetHeight;for(;null!==a&&"HTML"!==a.tagName;){if(n=window.getComputedStyle(a),t=n.getPropertyValue("position"),o=n.getPropertyValue("transform"),"static"!==t&&null===r&&(r=a),o&&"none"!==o&&null===s&&(s=a),"fixed"===t){r=s;break}a=a.parentNode}const p=this.createDialogBox(this.directiveElementRef.nativeElement,"fixed"!==t);if(this.useRootViewContainer||"fixed"===t&&(!r||r instanceof HTMLUnknownElement))this.top=p.top,this.left=p.left;else{null===r&&(r=a);const T=this.createDialogBox(r,"fixed"!==t);this.top=p.top-T.top,this.left=p.left-T.left}"fixed"===t&&(this.position="fixed");let F=this.cpPosition;const _=this.dialogElement.nativeElement.getBoundingClientRect();switch("auto"===this.cpPosition&&(F=function je(i,l){let t="right",o="bottom";const{height:n,width:r}=i,{top:s,left:a}=l,d=s+l.height,p=a+l.width,F=s-n<0,_=d+n>(window.innerHeight||document.documentElement.clientHeight),C=a-r<0,E=p+r>(window.innerWidth||document.documentElement.clientWidth);return _&&(o="top"),F&&(o="bottom"),C&&(t="right"),E&&(t="left"),F&&_&&C&&E?["left","right","top","bottom"].reduce((X,T)=>i[X]>i[T]?X:T):C&&E?F?"bottom":_||s>d?"top":"bottom":F&&_?C?"right":E||a>p?"left":"right":`${o}-${t}`}(_,this.cpTriggerElement.nativeElement.getBoundingClientRect())),this.arrowTop="top"===F?d-1:void 0,this.cpArrowPosition=void 0,F){case"top":this.top-=d+this.dialogArrowSize,this.left+=this.cpPositionOffset/100*p.width-this.dialogArrowOffset;break;case"bottom":this.top+=p.height+this.dialogArrowSize,this.left+=this.cpPositionOffset/100*p.width-this.dialogArrowOffset;break;case"top-left":case"left-top":this.top-=d-p.height+p.height*this.cpPositionOffset/100,this.left-=this.cpWidth+this.dialogArrowSize-2-this.dialogArrowOffset;break;case"top-right":case"right-top":this.top-=d-p.height+p.height*this.cpPositionOffset/100,this.left+=p.width+this.dialogArrowSize-2-this.dialogArrowOffset;break;case"left":case"bottom-left":case"left-bottom":this.top+=p.height*this.cpPositionOffset/100-this.dialogArrowOffset,this.left-=this.cpWidth+this.dialogArrowSize-2;break;default:this.top+=p.height*this.cpPositionOffset/100-this.dialogArrowOffset,this.left+=p.width+this.dialogArrowSize-2}const C=window.innerHeight,E=window.innerWidth,w=this.elRef.nativeElement.getBoundingClientRect();this.top+_.height>C&&(this.top=C-_.height,this.cpArrowPosition=w.x/2-20),this.left+_.width>E&&(this.left=E-_.width,this.cpArrowPosition=w.x/2-20),this.cpUsePosition=F}}isDescendant(t,o){let n=o.parentNode;for(;null!==n;){if(n===t)return!0;n=n.parentNode}return!1}createDialogBox(t,o){const{top:n,left:r}=t.getBoundingClientRect();return{top:n+(o?window.pageYOffset:0),left:r+(o?window.pageXOffset:0),width:t.offsetWidth,height:t.offsetHeight}}static \u0275fac=function(o){return new(o||i)(e.rXU(e.SKi),e.rXU(e.aKT),e.rXU(e.gRc),e.rXU(h.qQ),e.rXU(e.Agw),e.rXU(J))};static \u0275cmp=e.VBU({type:i,selectors:[["color-picker"]],viewQuery:function(o,n){if(1&o&&(e.GBs(R,7),e.GBs(H,7),e.GBs(P,7)),2&o){let r;e.mGM(r=e.lsd())&&(n.dialogElement=r.first),e.mGM(r=e.lsd())&&(n.hueSlider=r.first),e.mGM(r=e.lsd())&&(n.alphaSlider=r.first)}},hostBindings:function(o,n){1&o&&e.bIt("keyup.esc",function(s){return n.handleEsc(s)},!1,e.EBC)("keyup.enter",function(s){return n.handleEnter(s)},!1,e.EBC)},decls:30,vars:51,consts:[["dialogPopup",""],["hueSlider",""],["valueSlider",""],["alphaSlider",""],[1,"color-picker",3,"click"],[3,"left","class","top",4,"ngIf"],["class","saturation-lightness",3,"slider","rgX","rgY","background-color","newValue","dragStart","dragEnd",4,"ngIf"],[1,"hue-alpha","box"],[1,"left"],[1,"selected-color-background"],[1,"selected-color",3,"click"],["class","eyedropper-icon","xmlns","http://www.w3.org/2000/svg","height","24px","viewBox","0 0 24 24","width","24px","fill","#000000",4,"ngIf"],["type","button",3,"class","disabled","click",4,"ngIf"],[1,"right"],["style","height: 16px;",4,"ngIf"],[1,"hue",3,"newValue","dragStart","dragEnd","slider","rgX"],[1,"cursor"],[1,"value",3,"newValue","dragStart","dragEnd","slider","rgX"],[1,"alpha",3,"newValue","dragStart","dragEnd","slider","rgX"],["class","cmyk-text",3,"display",4,"ngIf"],["class","hsla-text",3,"display",4,"ngIf"],["class","rgba-text",3,"display",4,"ngIf"],["class","hex-text",3,"hex-alpha","display",4,"ngIf"],["class","value-text",4,"ngIf"],["class","type-policy",4,"ngIf"],["class","preset-area",4,"ngIf"],["class","button-area",4,"ngIf"],["class","extra-template",4,"ngIf"],[1,"saturation-lightness",3,"newValue","dragStart","dragEnd","slider","rgX","rgY"],["xmlns","http://www.w3.org/2000/svg","height","24px","viewBox","0 0 24 24","width","24px","fill","#000000",1,"eyedropper-icon"],["d","M0 0h24v24H0V0z","fill","none"],["d","M17.66 5.41l.92.92-2.69 2.69-.92-.92 2.69-2.69M17.67 3c-.26 0-.51.1-.71.29l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42l-2.34-2.34c-.2-.19-.45-.29-.7-.29zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z"],["type","button",3,"click","disabled"],[2,"height","16px"],[1,"cmyk-text"],[1,"box"],["type","number","pattern","[0-9]*","min","0","max","100",3,"keyup.enter","newValue","text","rg","value"],["type","number","pattern","[0-9]+([\\.,][0-9]{1,2})?","min","0","max","1","step","0.1",3,"text","rg","value","keyup.enter","newValue",4,"ngIf"],[4,"ngIf"],["type","number","pattern","[0-9]+([\\.,][0-9]{1,2})?","min","0","max","1","step","0.1",3,"keyup.enter","newValue","text","rg","value"],[1,"hsla-text"],["type","number","pattern","[0-9]*","min","0","max","360",3,"keyup.enter","newValue","text","rg","value"],[1,"rgba-text"],["type","number","pattern","[0-9]*","min","0","max","255",3,"keyup.enter","newValue","text","rg","value"],[1,"hex-text"],[3,"blur","keyup.enter","newValue","text","value"],[1,"value-text"],[1,"type-policy"],[1,"type-policy-arrow",3,"click"],[1,"preset-area"],[1,"preset-label"],[3,"class",4,"ngIf"],["class","preset-color",3,"backgroundColor","click",4,"ngFor","ngForOf"],[1,"preset-color",3,"click"],[3,"class","click",4,"ngIf"],[3,"click"],[1,"button-area"],["type","button",3,"class","click",4,"ngIf"],["type","button",3,"click"],[1,"extra-template"],[4,"ngTemplateOutlet"]],template:function(o,n){if(1&o){const r=e.RV6();e.j41(0,"div",4,0),e.bIt("click",function(a){return e.eBV(r),e.Njj(a.stopPropagation())}),e.DNE(2,y,1,7,"div",5)(3,z,2,8,"div",6),e.j41(4,"div",7)(5,"div",8),e.nrm(6,"div",9),e.j41(7,"div",10),e.bIt("click",function(){return e.eBV(r),e.Njj(n.eyeDropperSupported&&n.cpEyeDropper&&n.onEyeDropper())}),e.DNE(8,M,3,0,"svg",11),e.k0s(),e.DNE(9,u,2,5,"button",12),e.k0s(),e.j41(10,"div",13),e.DNE(11,g,1,0,"div",14),e.j41(12,"div",15,1),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onHueChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("hue"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("hue"))}),e.nrm(14,"div",16),e.k0s(),e.j41(15,"div",17,2),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onValueChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("value"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("value"))}),e.nrm(17,"div",16),e.k0s(),e.j41(18,"div",18,3),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onAlphaChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("alpha"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("alpha"))}),e.nrm(20,"div",16),e.k0s()()(),e.DNE(21,b,17,12,"div",19)(22,G,14,10,"div",20)(23,S,14,10,"div",21)(24,ge,8,7,"div",22)(25,he,9,3,"div",23)(26,fe,3,0,"div",24)(27,be,6,3,"div",25)(28,ye,3,2,"div",26)(29,we,2,1,"div",27),e.k0s()}2&o&&(e.xc7("display",n.show?"block":"none")("visibility",n.hidden?"hidden":"visible")("top",n.top,"px")("left",n.left,"px")("position",n.position)("height",n.cpHeight,"px")("width",n.cpWidth,"px"),e.AVh("open",n.show),e.R7$(2),e.Y8G("ngIf","popup"===n.cpDialogDisplay),e.R7$(),e.Y8G("ngIf",1===(n.cpColorMode||1)),e.R7$(4),e.xc7("background-color",n.selectedColor)("cursor",n.eyeDropperSupported&&n.cpEyeDropper?"pointer":null),e.R7$(),e.Y8G("ngIf",n.eyeDropperSupported&&n.cpEyeDropper),e.R7$(),e.Y8G("ngIf",n.cpAddColorButton),e.R7$(2),e.Y8G("ngIf","disabled"===n.cpAlphaChannel),e.R7$(),e.xc7("display",1===(n.cpColorMode||1)?"block":"none"),e.Y8G("rgX",1),e.R7$(2),e.xc7("left",null==n.slider?null:n.slider.h,"px"),e.R7$(),e.xc7("display",2===(n.cpColorMode||1)?"block":"none"),e.Y8G("rgX",1),e.R7$(2),e.xc7("right",null==n.slider?null:n.slider.v,"px"),e.R7$(),e.xc7("display","disabled"===n.cpAlphaChannel?"none":"block")("background-color",n.alphaSliderColor),e.Y8G("rgX",1),e.R7$(2),e.xc7("left",null==n.slider?null:n.slider.a,"px"),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&2===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",(null==n.cpPresetColors?null:n.cpPresetColors.length)||n.cpAddColorButton),e.R7$(),e.Y8G("ngIf",n.cpOKButton||n.cpCancelButton),e.R7$(),e.Y8G("ngIf",n.cpExtraTemplate))},dependencies:[h.Sq,h.bT,h.T3,Te,Ie],styles:['.color-picker{position:absolute;z-index:1000;width:230px;height:auto;border:#777 solid 1px;cursor:default;-webkit-user-select:none;user-select:none;background-color:#fff}.color-picker *{box-sizing:border-box;margin:0;font-size:11px}.color-picker input{width:0;height:26px;min-width:0;font-size:13px;text-align:center;color:#000}.color-picker input:invalid,.color-picker input:-moz-ui-invalid,.color-picker input:-moz-submit-invalid{box-shadow:none}.color-picker input::-webkit-inner-spin-button,.color-picker input::-webkit-outer-spin-button{margin:0;-webkit-appearance:none}.color-picker .arrow{position:absolute;z-index:999999;width:0;height:0;border-style:solid}.color-picker .arrow.arrow-top{left:8px;border-width:10px 5px;border-color:#777 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .arrow.arrow-bottom{top:-20px;left:8px;border-width:10px 5px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) #777 rgba(0,0,0,0)}.color-picker .arrow.arrow-top-left,.color-picker .arrow.arrow-left-top{right:-21px;bottom:8px;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.color-picker .arrow.arrow-top-right,.color-picker .arrow.arrow-right-top{bottom:8px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .arrow.arrow-left,.color-picker .arrow.arrow-left-bottom,.color-picker .arrow.arrow-bottom-left{top:8px;right:-21px;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.color-picker .arrow.arrow-right,.color-picker .arrow.arrow-right-bottom,.color-picker .arrow.arrow-bottom-right{top:8px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .cursor{position:relative;width:16px;height:16px;border:#222 solid 2px;border-radius:50%;cursor:default}.color-picker .box{display:flex;padding:4px 8px}.color-picker .left{position:relative;padding:16px 8px}.color-picker .right{flex:1 1 auto;padding:12px 8px}.color-picker .button-area{padding:0 16px 16px;text-align:right}.color-picker .button-area button{margin-left:8px}.color-picker .preset-area{padding:4px 15px}.color-picker .preset-area .preset-label{overflow:hidden;width:100%;padding:4px;font-size:11px;white-space:nowrap;text-align:left;text-overflow:ellipsis;color:#555}.color-picker .preset-area .preset-color{position:relative;display:inline-block;width:18px;height:18px;margin:4px 6px 8px;border:#a9a9a9 solid 1px;border-radius:25%;cursor:pointer}.color-picker .preset-area .preset-empty-message{min-height:18px;margin-top:4px;margin-bottom:8px;font-style:italic;text-align:center}.color-picker .hex-text{width:100%;padding:4px 8px;font-size:11px}.color-picker .hex-text .box{padding:0 24px 8px 8px}.color-picker .hex-text .box div{float:left;flex:1 1 auto;text-align:center;color:#555;clear:left}.color-picker .hex-text .box input{flex:1 1 auto;padding:1px;border:#a9a9a9 solid 1px}.color-picker .hex-alpha .box div:first-child,.color-picker .hex-alpha .box input:first-child{flex-grow:3;margin-right:8px}.color-picker .cmyk-text,.color-picker .hsla-text,.color-picker .rgba-text,.color-picker .value-text{width:100%;padding:4px 8px;font-size:11px}.color-picker .cmyk-text .box,.color-picker .hsla-text .box,.color-picker .rgba-text .box{padding:0 24px 8px 8px}.color-picker .value-text .box{padding:0 8px 8px}.color-picker .cmyk-text .box div,.color-picker .hsla-text .box div,.color-picker .rgba-text .box div,.color-picker .value-text .box div{flex:1 1 auto;margin-right:8px;text-align:center;color:#555}.color-picker .cmyk-text .box div:last-child,.color-picker .hsla-text .box div:last-child,.color-picker .rgba-text .box div:last-child,.color-picker .value-text .box div:last-child{margin-right:0}.color-picker .cmyk-text .box input,.color-picker .hsla-text .box input,.color-picker .rgba-text .box input,.color-picker .value-text .box input{float:left;flex:1;padding:1px;margin:0 8px 0 0;border:#a9a9a9 solid 1px}.color-picker .cmyk-text .box input:last-child,.color-picker .hsla-text .box input:last-child,.color-picker .rgba-text .box input:last-child,.color-picker .value-text .box input:last-child{margin-right:0}.color-picker .hue-alpha{align-items:center;margin-bottom:3px}.color-picker .hue{direction:ltr;width:100%;height:16px;margin-bottom:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwkUFWbCCAAAAFxJREFUaN7t0kEKg0AQAME2x83/n2qu5qCgD1iDhCoYdpnbQC9bbY1qVO/jvc6k3ad91s7/7F1/csgPrujuQ17BDYSFsBAWwgJhISyEBcJCWAgLhIWwEBYIi2f7Ar/1TCgFH2X9AAAAAElFTkSuQmCC)}.color-picker .value{direction:rtl;width:100%;height:16px;margin-bottom:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAACTklEQVR42u3SYUcrABhA4U2SkmRJMmWSJklKJiWZZpKUJJskKUmaTFImKZOUzMySpGRmliRNJilJSpKSJEtmSpIpmWmSdO736/6D+x7OP3gUCoWCv1cqlSQlJZGcnExKSgqpqamkpaWRnp5ORkYGmZmZqFQqsrKyyM7OJicnh9zcXNRqNXl5eeTn56PRaCgoKKCwsJCioiK0Wi3FxcWUlJRQWlpKWVkZ5eXlVFRUUFlZiU6no6qqiurqampqaqitraWurg69Xk99fT0GgwGj0UhDQwONjY00NTXR3NxMS0sLra2ttLW10d7ejslkwmw209HRQWdnJ11dXXR3d9PT00Nvby99fX309/czMDDA4OAgFouFoaEhrFYrw8PDjIyMMDo6ytjYGDabjfHxcSYmJpicnGRqagq73c709DQzMzPMzs4yNzfH/Pw8DocDp9OJy+XC7XazsLDA4uIiS0tLLC8vs7KywurqKmtra3g8HrxeLz6fD7/fz/r6OhsbG2xubrK1tcX29jaBQICdnR2CwSC7u7vs7e2xv7/PwcEBh4eHHB0dcXx8zMnJCaenp5ydnXF+fs7FxQWXl5dcXV1xfX3Nzc0Nt7e33N3dEQqFuL+/5+HhgXA4TCQS4fHxkaenJ56fn3l5eeH19ZVoNMrb2xvv7+98fHwQi8WIx+N8fn6SSCT4+vri+/ubn58ffn9/+VcKgSWwBJbAElgCS2AJLIElsASWwBJYAktgCSyBJbAElsASWAJLYAksgSWwBJbAElgCS2AJLIElsP4/WH8AmJ5Z6jHS4h8AAAAASUVORK5CYII=)}.color-picker .alpha{direction:ltr;width:100%;height:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwYQlZMa3gAAAWVJREFUaN7tmEGO6jAQRCsOArHgBpyAJYGjcGocxAm4A2IHpmoWE0eBH+ezmFlNvU06shJ3W6VEelWMUQAIIF9f6qZpimsA1LYtS2uF51/u27YVAFZVRUkEoGHdPV/sIcbIEIIkUdI/9Xa7neyv61+SWFUVAVCSct00TWn2fv6u3+Ecfd3tXzy/0+nEUu+SPjo/kqzrmiQpScN6v98XewfA8/lMkiLJ2WxGSUopcT6fM6U0NX9/frfbjev1WtfrlZfLhYfDQQHG/AIOlnGwjINlHCxjHCzjYJm/TJWdCwquJXseFFzGwDNNeiKMOJTO8xQdDQaeB29+K9efeLaBo9J7vdvtJj1RjFFjfiv7qv95tjx/7leSQgh93e1ffMeIp6O+YQjho/N791t1XVOSSI7N//K+4/GoxWLBx+PB5/Op5XLJ+/3OlJJWqxU3m83ovv5iGf8KjYNlHCxjHCzjYBkHy5gf5gusvQU7U37jTAAAAABJRU5ErkJggg==)}.color-picker .type-policy{position:absolute;top:218px;right:12px;width:16px;height:24px;background-size:8px 16px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAYAAAAffCjxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAACewAAAnsB01CO3AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIASURBVEiJ7ZY9axRRFIafsxMStrLQJpAgpBFhi+C9w1YSo00I6RZ/g9vZpBf/QOr4GyRgkSKNSrAadsZqQGwCkuAWyRZJsySwvhZ7N/vhzrgbLH3Ld8597jlzz50zJokyxXH8DqDVar0qi6v8BbItqSGpEcfxdlmsFWXkvX8AfAVWg3UKPEnT9GKujMzsAFgZsVaCN1VTQd77XUnrgE1kv+6935268WRpzrnHZvYRWC7YvC3pRZZl3wozqtVqiyH9IgjAspkd1Gq1xUJQtVrdB9ZKIAOthdg/Qc65LUk7wNIMoCVJO865rYFhkqjX6/d7vV4GPJwBMqofURS5JEk6FYBer/eeYb/Mo9WwFnPOvQbeAvfuAAK4BN4sAJtAG/gJIElmNuiJyba3EGNmZiPeZuEVmVell/Y/6N+CzDn3AXhEOOo7Hv/3BeAz8IzQkMPnJbuPx1wC+yYJ7/0nYIP5S/0FHKdp+rwCEEXRS/rf5Hl1Gtb2M0iSpCOpCZzPATmX1EySpHMLAsiy7MjMDoHrGSDXZnaYZdnRwBh7J91utwmczAA6CbG3GgPleX4jqUH/a1CktqRGnuc3hSCAMB32gKspkCtgb3KCQMmkjeP4WNJThrNNZval1WptTIsv7JtQ4tmIdRa8qSoEpWl6YWZNoAN0zKxZNPehpLSBZv2t+Q0CJ9lLnARQLAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:center}.color-picker .type-policy .type-policy-arrow{display:block;width:100%;height:50%}.color-picker .selected-color{position:absolute;top:16px;left:8px;width:40px;height:40px;border:1px solid #a9a9a9;border-radius:50%}.color-picker .selected-color-background{width:40px;height:40px;border-radius:50%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAh0lEQVRYR+2W0QlAMQgD60zdfwOdqa8TmI/wQMr5K0I5bZLIzLOa2nt37VVVbd+dDx5obgCC3KBLwJ2ff4PnVidkf+ucIhw80HQaCLo3DMH3CRK3iFsmAWVl6hPNDwt8EvNE5q+YuEXcMgkonVM6SdyCoEvAnZ8v1Hjx817MilmxSUB5rdLJDycZgUAZUch/AAAAAElFTkSuQmCC)}.color-picker .saturation-lightness{direction:ltr;width:100%;height:130px;border:none;cursor:pointer;touch-action:manipulation;background-size:100% 100%;background-image:url(data:image/png;base64,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)}.color-picker .cp-add-color-button-class{position:absolute;display:inline;padding:0;margin:3px -3px;border:0;cursor:pointer;background:transparent}.color-picker .cp-add-color-button-class:hover{text-decoration:underline}.color-picker .cp-add-color-button-class:disabled{cursor:not-allowed;color:#999}.color-picker .cp-add-color-button-class:disabled:hover{text-decoration:none}.color-picker .cp-remove-color-button-class{position:absolute;top:-5px;right:-5px;display:block;width:10px;height:10px;border-radius:50%;cursor:pointer;text-align:center;background:#fff;box-shadow:1px 1px 5px #333}.color-picker .cp-remove-color-button-class:before{content:"x";position:relative;bottom:3.5px;display:inline-block;font-size:10px}.color-picker .eyedropper-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);fill:#fff;mix-blend-mode:exclusion}\n'],encapsulation:2})}return i})(),Be=(()=>{class i{injector;cfr;appRef;vcRef;elRef;_service;dialog;dialogCreated=!1;ignoreChanges=!1;cmpRef;viewAttachedToAppRef=!1;colorPicker;cpWidth="230px";cpHeight="auto";cpToggle=!1;cpDisabled=!1;cpIgnoredElements=[];cpFallbackColor="";cpColorMode="color";cpCmykEnabled=!1;cpOutputFormat="auto";cpAlphaChannel="enabled";cpDisableInput=!1;cpDialogDisplay="popup";cpSaveClickOutside=!0;cpCloseClickOutside=!0;cpUseRootViewContainer=!1;cpPosition="auto";cpPositionOffset="0%";cpPositionRelativeToArrow=!1;cpOKButton=!1;cpOKButtonText="OK";cpOKButtonClass="cp-ok-button-class";cpCancelButton=!1;cpCancelButtonText="Cancel";cpCancelButtonClass="cp-cancel-button-class";cpEyeDropper=!1;cpPresetLabel="Preset colors";cpPresetColors;cpPresetColorsClass="cp-preset-colors-class";cpMaxPresetColorsLength=6;cpPresetEmptyMessage="No colors added";cpPresetEmptyMessageClass="preset-empty-message";cpAddColorButton=!1;cpAddColorButtonText="Add color";cpAddColorButtonClass="cp-add-color-button-class";cpRemoveColorButtonClass="cp-remove-color-button-class";cpArrowPosition=0;cpExtraTemplate;cpInputChange=new e.bkB(!0);cpToggleChange=new e.bkB(!0);cpSliderChange=new e.bkB(!0);cpSliderDragEnd=new e.bkB(!0);cpSliderDragStart=new e.bkB(!0);colorPickerOpen=new e.bkB(!0);colorPickerClose=new e.bkB(!0);colorPickerCancel=new e.bkB(!0);colorPickerSelect=new e.bkB(!0);colorPickerChange=new e.bkB(!1);cpCmykColorChange=new e.bkB(!0);cpPresetColorsChange=new e.bkB(!0);handleClick(){this.inputFocus()}handleFocus(){this.inputFocus()}handleInput(t){this.inputChange(t)}constructor(t,o,n,r,s,a){this.injector=t,this.cfr=o,this.appRef=n,this.vcRef=r,this.elRef=s,this._service=a}ngOnDestroy(){null!=this.cmpRef&&(this.viewAttachedToAppRef&&this.appRef.detachView(this.cmpRef.hostView),this.cmpRef.destroy(),this.cmpRef=null,this.dialog=null)}ngOnChanges(t){t.cpToggle&&!this.cpDisabled&&(t.cpToggle.currentValue?this.openDialog():t.cpToggle.currentValue||this.closeDialog()),t.colorPicker&&(this.dialog&&!this.ignoreChanges&&("inline"===this.cpDialogDisplay&&this.dialog.setInitialColor(t.colorPicker.currentValue),this.dialog.setColorFromString(t.colorPicker.currentValue,!1),this.cpUseRootViewContainer&&"inline"!==this.cpDialogDisplay&&this.cmpRef.changeDetectorRef.detectChanges()),this.ignoreChanges=!1),(t.cpPresetLabel||t.cpPresetColors)&&this.dialog&&this.dialog.setPresetConfig(this.cpPresetLabel,this.cpPresetColors)}openDialog(){if(this.dialogCreated)this.dialog&&this.dialog.openDialog(this.colorPicker);else{let t=this.vcRef;if(this.dialogCreated=!0,this.viewAttachedToAppRef=!1,this.cpUseRootViewContainer&&"inline"!==this.cpDialogDisplay){const r=this.injector.get(this.appRef.componentTypes[0],e.zZn.NULL);r!==e.zZn.NULL?t=r.vcRef||r.viewContainerRef||this.vcRef:this.viewAttachedToAppRef=!0}const o=this.cfr.resolveComponentFactory(Re);if(this.viewAttachedToAppRef)this.cmpRef=o.create(this.injector),this.appRef.attachView(this.cmpRef.hostView),document.body.appendChild(this.cmpRef.hostView.rootNodes[0]);else{const n=e.zZn.create({providers:[],parent:t.injector});this.cmpRef=t.createComponent(o,0,n,[])}this.cmpRef.instance.setupDialog(this,this.elRef,this.colorPicker,this.cpWidth,this.cpHeight,this.cpDialogDisplay,this.cpFallbackColor,this.cpColorMode,this.cpCmykEnabled,this.cpAlphaChannel,this.cpOutputFormat,this.cpDisableInput,this.cpIgnoredElements,this.cpSaveClickOutside,this.cpCloseClickOutside,this.cpUseRootViewContainer,this.cpPosition,this.cpPositionOffset,this.cpPositionRelativeToArrow,this.cpPresetLabel,this.cpPresetColors,this.cpPresetColorsClass,this.cpMaxPresetColorsLength,this.cpPresetEmptyMessage,this.cpPresetEmptyMessageClass,this.cpOKButton,this.cpOKButtonClass,this.cpOKButtonText,this.cpCancelButton,this.cpCancelButtonClass,this.cpCancelButtonText,this.cpAddColorButton,this.cpAddColorButtonClass,this.cpAddColorButtonText,this.cpRemoveColorButtonClass,this.cpEyeDropper,this.elRef,this.cpExtraTemplate),this.dialog=this.cmpRef.instance,this.vcRef!==t&&this.cmpRef.changeDetectorRef.detectChanges()}}closeDialog(){this.dialog&&"popup"===this.cpDialogDisplay&&this.dialog.closeDialog()}cmykChanged(t){this.cpCmykColorChange.emit(t)}stateChanged(t){this.cpToggleChange.emit(t),t?this.colorPickerOpen.emit(this.colorPicker):this.colorPickerClose.emit(this.colorPicker)}colorChanged(t,o=!0){this.ignoreChanges=o,this.colorPickerChange.emit(t)}colorSelected(t){this.colorPickerSelect.emit(t)}colorCanceled(){this.colorPickerCancel.emit()}inputFocus(){const t=this.elRef.nativeElement,o=this.cpIgnoredElements.filter(n=>n===t);!this.cpDisabled&&!o.length&&(typeof document<"u"&&t===document.activeElement?this.openDialog():this.dialog&&this.dialog.show?this.closeDialog():this.openDialog())}inputChange(t){this.dialog?this.dialog.setColorFromString(t.target.value,!0):(this.colorPicker=t.target.value,this.colorPickerChange.emit(this.colorPicker))}inputChanged(t){this.cpInputChange.emit(t)}sliderChanged(t){this.cpSliderChange.emit(t)}sliderDragEnd(t){this.cpSliderDragEnd.emit(t)}sliderDragStart(t){this.cpSliderDragStart.emit(t)}presetColorsChanged(t){this.cpPresetColorsChange.emit(t)}static \u0275fac=function(o){return new(o||i)(e.rXU(e.zZn),e.rXU(e.OM3),e.rXU(e.o8S),e.rXU(e.c1b),e.rXU(e.aKT),e.rXU(J))};static \u0275dir=e.FsC({type:i,selectors:[["","colorPicker",""]],hostBindings:function(o,n){1&o&&e.bIt("click",function(){return n.handleClick()})("focus",function(){return n.handleFocus()})("input",function(s){return n.handleInput(s)})},inputs:{colorPicker:"colorPicker",cpWidth:"cpWidth",cpHeight:"cpHeight",cpToggle:"cpToggle",cpDisabled:"cpDisabled",cpIgnoredElements:"cpIgnoredElements",cpFallbackColor:"cpFallbackColor",cpColorMode:"cpColorMode",cpCmykEnabled:"cpCmykEnabled",cpOutputFormat:"cpOutputFormat",cpAlphaChannel:"cpAlphaChannel",cpDisableInput:"cpDisableInput",cpDialogDisplay:"cpDialogDisplay",cpSaveClickOutside:"cpSaveClickOutside",cpCloseClickOutside:"cpCloseClickOutside",cpUseRootViewContainer:"cpUseRootViewContainer",cpPosition:"cpPosition",cpPositionOffset:"cpPositionOffset",cpPositionRelativeToArrow:"cpPositionRelativeToArrow",cpOKButton:"cpOKButton",cpOKButtonText:"cpOKButtonText",cpOKButtonClass:"cpOKButtonClass",cpCancelButton:"cpCancelButton",cpCancelButtonText:"cpCancelButtonText",cpCancelButtonClass:"cpCancelButtonClass",cpEyeDropper:"cpEyeDropper",cpPresetLabel:"cpPresetLabel",cpPresetColors:"cpPresetColors",cpPresetColorsClass:"cpPresetColorsClass",cpMaxPresetColorsLength:"cpMaxPresetColorsLength",cpPresetEmptyMessage:"cpPresetEmptyMessage",cpPresetEmptyMessageClass:"cpPresetEmptyMessageClass",cpAddColorButton:"cpAddColorButton",cpAddColorButtonText:"cpAddColorButtonText",cpAddColorButtonClass:"cpAddColorButtonClass",cpRemoveColorButtonClass:"cpRemoveColorButtonClass",cpArrowPosition:"cpArrowPosition",cpExtraTemplate:"cpExtraTemplate"},outputs:{cpInputChange:"cpInputChange",cpToggleChange:"cpToggleChange",cpSliderChange:"cpSliderChange",cpSliderDragEnd:"cpSliderDragEnd",cpSliderDragStart:"cpSliderDragStart",colorPickerOpen:"colorPickerOpen",colorPickerClose:"colorPickerClose",colorPickerCancel:"colorPickerCancel",colorPickerSelect:"colorPickerSelect",colorPickerChange:"colorPickerChange",cpCmykColorChange:"cpCmykColorChange",cpPresetColorsChange:"cpPresetColorsChange"},exportAs:["ngxColorPicker"],features:[e.OA$]})}return i})(),Ve=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({providers:[J],imports:[h.MD]})}return i})();var De=m(2578);let Q;try{Q=!!new Blob}catch{Q=!1}let re=(()=>{class i{get isFileSaverSupported(){return Q}genType(t){if(!t||-1===t.lastIndexOf("."))return"text/plain";const o=t.substring(t.lastIndexOf(".")+1);switch(o){case"txt":return"text/plain";case"xml":case"html":return`text/${o}`;case"json":return"octet/stream";default:return`application/${o}`}}save(t,o,n,r){if(!t)throw new Error("Data argument should be a blob instance");const s=new Blob([t],{type:n||t.type||this.genType(o)});(0,De.saveAs)(s,decodeURI(o||"download"),r)}saveText(t,o,n){const r=new Blob([t]);this.save(r,o,void 0,n)}static#e=this.\u0275fac=function(o){return new(o||i)};static#t=this.\u0275prov=e.jDH({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),Pe=(()=>{class i{static#e=this.\u0275fac=function(o){return new(o||i)};static#t=this.\u0275mod=e.$C({type:i});static#n=this.\u0275inj=e.G2t({})}return i})();const Me=i=>["segment",i],Ge=(i,l)=>({"segment-main":!0,expandable:i,expanded:l});function Ne(i,l){1&i&&e.nrm(0,"div",9)}function Oe(i,l){if(1&i&&(e.j41(0,"span",10),e.EFF(1),e.k0s()),2&i){const t=e.XpG().$implicit;e.R7$(),e.JRh(t.description)}}function Xe(i,l){if(1&i&&(e.j41(0,"section",11),e.nrm(1,"ngx-json-viewer",12),e.k0s()),2&i){const t=e.XpG().$implicit,o=e.XpG();e.R7$(),e.Y8G("json",t.value)("expanded",o.expanded)("depth",o.depth)("_currentDepth",o._currentDepth+1)}}function Ye(i,l){if(1&i){const t=e.RV6();e.j41(0,"section",2)(1,"section",3),e.bIt("click",function(){const n=e.eBV(t).$implicit,r=e.XpG();return e.Njj(r.toggle(n))}),e.DNE(2,Ne,1,0,"div",4),e.j41(3,"span",5),e.EFF(4),e.k0s(),e.j41(5,"span",6),e.EFF(6,": "),e.k0s(),e.DNE(7,Oe,2,1,"span",7),e.k0s(),e.DNE(8,Xe,2,4,"section",8),e.k0s()}if(2&i){const t=l.$implicit,o=e.XpG();e.Y8G("ngClass",e.eq3(6,Me,"segment-type-"+t.type)),e.R7$(),e.Y8G("ngClass",e.l_i(8,Ge,o.isExpandable(t),t.expanded)),e.R7$(),e.Y8G("ngIf",o.isExpandable(t)),e.R7$(2),e.JRh(t.key),e.R7$(3),e.Y8G("ngIf",!t.expanded||!o.isExpandable(t)),e.R7$(),e.Y8G("ngIf",t.expanded&&o.isExpandable(t))}}let se=(()=>{class i{constructor(){this.expanded=!0,this.depth=-1,this._currentDepth=0,this.segments=[]}ngOnChanges(){this.segments=[],this.json=this.decycle(this.json),"object"==typeof this.json?Object.keys(this.json).forEach(t=>{this.segments.push(this.parseKeyValue(t,this.json[t]))}):this.segments.push(this.parseKeyValue(`(${typeof this.json})`,this.json))}isExpandable(t){return"object"===t.type||"array"===t.type}toggle(t){this.isExpandable(t)&&(t.expanded=!t.expanded)}parseKeyValue(t,o){const n={key:t,value:o,type:void 0,description:""+o,expanded:this.isExpanded()};switch(typeof n.value){case"number":n.type="number";break;case"boolean":n.type="boolean";break;case"function":n.type="function";break;case"string":n.type="string",n.description='"'+n.value+'"';break;case"undefined":n.type="undefined",n.description="undefined";break;case"object":null===n.value?(n.type="null",n.description="null"):Array.isArray(n.value)?(n.type="array",n.description="Array["+n.value.length+"] "+JSON.stringify(n.value)):n.value instanceof Date?n.type="date":(n.type="object",n.description="Object "+JSON.stringify(n.value))}return n}isExpanded(){return this.expanded&&!(this.depth>-1&&this._currentDepth>=this.depth)}decycle(t){const o=new WeakMap;return function n(r,s){let a,d;return"object"!=typeof r||null===r||r instanceof Boolean||r instanceof Date||r instanceof Number||r instanceof RegExp||r instanceof String?r:(a=o.get(r),void 0!==a?{$ref:a}:(o.set(r,s),Array.isArray(r)?(d=[],r.forEach(function(p,F){d[F]=n(p,s+"["+F+"]")})):(d={},Object.keys(r).forEach(function(p){d[p]=n(r[p],s+"["+JSON.stringify(p)+"]")})),d))}(t,"$")}}return i.\u0275fac=function(t){return new(t||i)},i.\u0275cmp=e.VBU({type:i,selectors:[["ngx-json-viewer"]],inputs:{json:"json",expanded:"expanded",depth:"depth",_currentDepth:"_currentDepth"},features:[e.OA$],decls:2,vars:1,consts:[[1,"ngx-json-viewer"],[3,"ngClass",4,"ngFor","ngForOf"],[3,"ngClass"],[3,"click","ngClass"],["class","toggler",4,"ngIf"],[1,"segment-key"],[1,"segment-separator"],["class","segment-value",4,"ngIf"],["class","children",4,"ngIf"],[1,"toggler"],[1,"segment-value"],[1,"children"],[3,"json","expanded","depth","_currentDepth"]],template:function(t,o){1&t&&(e.j41(0,"section",0),e.DNE(1,Ye,9,11,"section",1),e.k0s()),2&t&&(e.R7$(),e.Y8G("ngForOf",o.segments))},dependencies:[h.YU,h.Sq,h.bT,i],styles:['@charset "UTF-8";.ngx-json-viewer[_ngcontent-%COMP%]{font-family:var(--ngx-json-font-family, monospace);font-size:var(--ngx-json-font-size, 1em);width:100%;height:100%;overflow:hidden;position:relative}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%]{padding:2px;margin:1px 1px 1px 12px}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%]{word-wrap:break-word}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .toggler[_ngcontent-%COMP%]{position:absolute;margin-left:-14px;margin-top:3px;font-size:.8em;line-height:1.2em;vertical-align:middle;color:var(--ngx-json-toggler, #787878)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .toggler[_ngcontent-%COMP%]:after{display:inline-block;content:"\\25ba";transition:transform .1s ease-in}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-key[_ngcontent-%COMP%]{color:var(--ngx-json-key, #4E187C)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-separator[_ngcontent-%COMP%]{color:var(--ngx-json-separator, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-value, #000)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .children[_ngcontent-%COMP%]{margin-left:12px}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-string[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-string, #FF6B6B)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-number[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-number, #009688)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-boolean[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-boolean, #B938A4)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-date[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-date, #05668D)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-array[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-array, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-object[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-object, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-function[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-function, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-null[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-null, #fff)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-undefined, #fff)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-null[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{background-color:var(--ngx-json-null-bg, red)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-key[_ngcontent-%COMP%]{color:var(--ngx-json-undefined-key, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{background-color:var(--ngx-json-undefined-key, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-object[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%], .ngx-json-viewer[_ngcontent-%COMP%] .segment-type-array[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%]{white-space:nowrap}.ngx-json-viewer[_ngcontent-%COMP%] .expanded[_ngcontent-%COMP%] > .toggler[_ngcontent-%COMP%]:after{transform:rotate(90deg)}.ngx-json-viewer[_ngcontent-%COMP%] .expandable[_ngcontent-%COMP%], .ngx-json-viewer[_ngcontent-%COMP%] .expandable[_ngcontent-%COMP%] > .toggler[_ngcontent-%COMP%]{cursor:pointer}']}),i})(),qe=(()=>{class i{}return i.\u0275fac=function(t){return new(t||i)},i.\u0275mod=e.$C({type:i}),i.\u0275inj=e.G2t({imports:[h.MD]}),i})();var le=m(93331),V=m(38117),c=m(89417),He=m(28990),ze=m(96354),A=m(3366),v=m(19664),D=m(45794),I=m(97013);function Ue(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2,"\n "),e.j41(3,"b"),e.EFF(4,"Device name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"IEEE"),e.k0s(),e.EFF(8),e.j41(9,"b"),e.EFF(10,"Ep"),e.k0s(),e.EFF(11),e.j41(12,"b"),e.EFF(13,"Nwkid"),e.k0s(),e.EFF(14),e.k0s(),e.EFF(15,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t.IEEE," - "),e.R7$(3),e.SpI(" :\n ",t.Ep," - "),e.R7$(3),e.SpI(" : ",t.NwkId,"\n ")}}function Ke(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2,"\n "),e.j41(3,"b"),e.EFF(4,"Device name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"IEEE"),e.k0s(),e.EFF(8),e.j41(9,"b"),e.EFF(10,"Ep"),e.k0s(),e.EFF(11),e.j41(12,"b"),e.EFF(13,"Nwkid"),e.k0s(),e.EFF(14),e.k0s(),e.EFF(15,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t.IEEE," - "),e.R7$(3),e.SpI(" :\n ",t.Ep," - "),e.R7$(3),e.SpI(" : ",t.NwkId,"\n ")}}const Le=new V.Vy("BindingComponent");let We=(()=>{class i extends He.U{apiService;formBuilder;translate;toastr;form;clusters$;devicesSource;devicesTarget;devicesTargetFiltered;constructor(t,o,n,r){super(),this.apiService=t,this.formBuilder=o,this.translate=n,this.toastr=r}ngOnInit(){this.form=this.formBuilder.group({source:[null,c.k0.required],target:[null,c.k0.required],cluster:[null,c.k0.required]}),this.clusters$=this.apiService.getBindLSTcluster().pipe((0,ze.T)(t=>t.map(o=>(o.fullName=o.ClusterId+" "+o.ClusterDesc,o)))),this.subs.sink=this.form.get("cluster").valueChanges.subscribe(t=>{Le.debug("change:",t),this.apiService.getBindLSTdevice(this.form.get("cluster").value).subscribe(o=>{this.devicesSource=o,this.devicesTarget=o})})}filterDevices(t){this.form.get("target").patchValue(null),this.devicesTargetFiltered=this.devicesTarget.filter(o=>t.NwkId!==o.NwkId)}putBinding(){const t={sourceIeee:this.form.get("source").value.IEEE,sourceEp:this.form.get("source").value.Ep,destIeee:this.form.get("target").value.IEEE,destEp:this.form.get("target").value.Ep,cluster:this.form.get("cluster").value};this.apiService.putBinding(t).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.update.notify")),this.form.reset("",{onlySelf:!0,emitEvent:!1})})}putUnBinding(){const t={sourceIeee:this.form.get("source").value.IEEE,sourceEp:this.form.get("source").value.Ep,destIeee:this.form.get("target").value.IEEE,destEp:this.form.get("target").value.Ep,cluster:this.form.get("cluster").value};this.apiService.putUnBinding(t).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.update.notify")),this.form.reset("",{onlySelf:!0,emitEvent:!1})})}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$),e.rXU(D.tw))};static \u0275cmp=e.VBU({type:i,selectors:[["app-binding"]],features:[e.Vt3],decls:71,vars:26,consts:[[1,"row","row-cols-1","row-cols-xxl-3","row-cols-lg-2","row-cols-md-1","row-cols-sm-1","g-4"],[3,"formGroup"],[1,"card"],["translate","tools.binding.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["appendTo","body","bindLabel","fullName","bindValue","ClusterId","formControlName","cluster",3,"items","multiple","closeOnSelect","placeholder"],[1,"row","mt-2"],["appendTo","body","bindLabel","ZDeviceName","formControlName","source",3,"change","items","multiple","closeOnSelect","placeholder"],["ng-option-tmp",""],["bindLabel","ZDeviceName","appendTo","body","formControlName","target",3,"items","multiple","closeOnSelect","placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.binding.button.put",1,"btn","btn-primary",3,"click","disabled"],["translate","tools.unbinding.button.put",1,"ms-2","btn","btn-primary",3,"click","disabled"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"form",1),e.EFF(3,"\n "),e.j41(4,"div",2),e.EFF(5,"\n "),e.nrm(6,"div",3),e.EFF(7,"\n "),e.j41(8,"div",4),e.EFF(9,"\n "),e.nrm(10,"p",5),e.nI1(11,"translate"),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"div",8),e.EFF(18,"\n "),e.j41(19,"div"),e.EFF(20,"\n "),e.j41(21,"ng-select",9),e.nI1(22,"translate"),e.nI1(23,"async"),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.j41(29,"div",10),e.EFF(30,"\n "),e.j41(31,"div",8),e.EFF(32,"\n "),e.j41(33,"div"),e.EFF(34,"\n "),e.j41(35,"ng-select",11),e.nI1(36,"translate"),e.bIt("change",function(s){return n.filterDevices(s)}),e.EFF(37,"\n "),e.DNE(38,Ue,16,4,"ng-template",12),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.j41(44,"div",10),e.EFF(45,"\n "),e.j41(46,"div",8),e.EFF(47,"\n "),e.j41(48,"div"),e.EFF(49,"\n "),e.j41(50,"ng-select",13),e.nI1(51,"translate"),e.EFF(52,"\n "),e.DNE(53,Ke,16,4,"ng-template",12),e.EFF(54,"\n "),e.k0s(),e.EFF(55,"\n "),e.k0s(),e.EFF(56,"\n "),e.k0s(),e.EFF(57,"\n "),e.k0s(),e.EFF(58,"\n "),e.k0s(),e.EFF(59,"\n "),e.k0s(),e.EFF(60,"\n "),e.j41(61,"div",14),e.EFF(62,"\n "),e.j41(63,"button",15),e.bIt("click",function(){return n.putBinding()}),e.k0s(),e.EFF(64,"\n "),e.j41(65,"button",16),e.bIt("click",function(){return n.putUnBinding()}),e.k0s(),e.EFF(66,"\n "),e.k0s(),e.EFF(67,"\n "),e.k0s(),e.EFF(68,"\n "),e.k0s(),e.EFF(69,"\n"),e.k0s(),e.EFF(70,"\n")),2&o&&(e.R7$(2),e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(11,16,"tools.binding.subtitle"),e.npT),e.R7$(11),e.FS9("placeholder",e.bMT(22,18,"tools.binding.cluster")),e.Y8G("items",e.bMT(23,20,n.clusters$))("multiple",!1)("closeOnSelect",!0),e.R7$(14),e.FS9("placeholder",e.bMT(36,22,"tools.binding.sourceEp")),e.Y8G("items",n.devicesSource)("multiple",!1)("closeOnSelect",!0),e.R7$(15),e.FS9("placeholder",e.bMT(51,24,"tools.binding.destEp")),e.Y8G("items",n.devicesTargetFiltered)("multiple",!1)("closeOnSelect",!0),e.R7$(13),e.Y8G("disabled",!n.form.valid),e.R7$(2),e.Y8G("disabled",!n.form.valid))},dependencies:[c.qT,c.BC,c.cb,c.j4,c.JD,I.vr,I.Uq,v.Mm,h.Jj,v.D9]})}return i})();function Ze(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId,"")}}function Je(i,l){if(1&i){const t=e.RV6();e.j41(0,"ng-select",18),e.nI1(1,"translate"),e.bIt("change",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.setAction(n))}),e.EFF(2,"\n "),e.k0s()}if(2&i){const t=e.XpG();e.FS9("placeholder",e.bMT(1,5,"tools.debugcommand.action")),e.Y8G("items",t.capabilities.Capabilities)("multiple",!1)("closeOnSelect",!0)("searchable",!0)}}function Qe(i,l){if(1&i&&(e.j41(0,"ng-select",19),e.nI1(1,"translate"),e.EFF(2,"\n "),e.k0s()),2&i){const t=e.XpG();e.FS9("placeholder",e.bMT(1,5,"tools.debugcommand.type")),e.Y8G("items",t.capabilities.Types)("multiple",!1)("closeOnSelect",!0)("searchable",!0)}}function $e(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.j41(6,"span",20),e.mxI("colorPickerChange",function(n){e.eBV(t);const r=e.XpG();return e.DH7(r.colorPicker,n)||(r.colorPicker=n),e.Njj(n)}),e.k0s(),e.EFF(7,"\n "),e.k0s(),e.EFF(8,"\n "),e.k0s(),e.EFF(9,"\n "),e.k0s()}if(2&i){const t=e.XpG();e.R7$(6),e.xc7("background",t.colorPicker),e.Y8G("cpToggle",!0)("cpDialogDisplay","inline"),e.R50("colorPicker",t.colorPicker),e.Y8G("cpOutputFormat","rgba")}}function et(i,l){1&i&&e.nrm(0,"div",23)}function tt(i,l){if(1&i&&(e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.nrm(6,"input",21),e.nI1(7,"translate"),e.EFF(8,"\n "),e.DNE(9,et,1,0,"div",22),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(6),e.FS9("placeholder",e.bMT(7,2,"tools.debugcommand.value")),e.R7$(3),e.Y8G("ngIf",t.form.controls.effect.errors)}}function nt(i,l){1&i&&e.nrm(0,"div",26)}function ot(i,l){if(1&i&&(e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.nrm(6,"input",24),e.nI1(7,"translate"),e.EFF(8,"\n "),e.DNE(9,nt,1,0,"div",25),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(6),e.FS9("placeholder",e.bMT(7,2,"tools.debugcommand.value")),e.R7$(3),e.Y8G("ngIf",!t.form.controls.level.valid)}}let it=(()=>{class i{toastr;apiService;formBuilder;translate;routers;capabilities;form;colorPicker="rgba(30,96,239,0.54)";capaSelected;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnInit(){this.form=this.formBuilder.group({level:[null,[c.k0.nullValidator,c.k0.min(0),c.k0.max(100)]],type:[null,c.k0.required],action:[null,c.k0.required],deviceSelected:[null,c.k0.required],effect:[null,c.k0.compose([c.k0.nullValidator,c.k0.pattern("^[0-9A-Fa-f]+")])]}),this.form.get("type").disable(),this.apiService.getZDevices().subscribe(t=>{this.routers=t.filter(o=>"Router"===o.LogicalType)})}callCapabilities(t){this.capaSelected=null,this.form.get("action").patchValue(null),this.form.get("type").patchValue(null),this.capabilities=null,this.apiService.getDevCap(t._NwkId).subscribe(o=>{this.capabilities=o})}setAction(t){this.capaSelected=t,this.form.get("type").patchValue(null),t&&!0===t.Type?this.form.get("type").enable():this.form.get("type").disable()}callAction(){let t=null,o=null;if(this.testRGB)if(this.colorPicker.startsWith("rgba")){let r=this.colorPicker.replace("rgba(","");r=r.replace(")","");const s=r.split(",");4===s.length&&(o=100*Number(s[3]),t="rgb("+s[0]+","+s[1]+","+s[2]+")")}else this.colorPicker.startsWith("rgb")&&(o=100,t=this.colorPicker);!o&&this.capaSelected.Value&&("hex"===this.capaSelected.Value&&(o=this.form.get("effect").value),"int"===this.capaSelected.Value&&(o=this.form.get("level").value));const n={NwkId:this.form.get("deviceSelected").value._NwkId,Command:this.form.get("action").value.actuator,Value:o,Color:t,Type:this.form.get("type").value};this.apiService.putDevCommand(n).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}get testRGB(){return!!this.form.get("type").value&&this.form.get("type").value.startsWith("ColorControl")}static \u0275fac=function(o){return new(o||i)(e.rXU(D.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-command"]],decls:61,vars:17,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.debugcommand.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["bindLabel","ZDeviceName","appendTo","body","formControlName","deviceSelected",3,"change","items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[1,"col-sm"],["translate","tools.debugcommand.button.cancel",1,"ms-3","btn","btn-secondary",3,"click"],[1,"row","mt-2"],["bindLabel","actuator","appendTo","body","formControlName","action",3,"items","multiple","closeOnSelect","searchable","placeholder","change",4,"ngIf"],["appendTo","body","formControlName","type",3,"items","multiple","closeOnSelect","searchable","placeholder",4,"ngIf"],["class","row mt-2",4,"ngIf"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.debugcommand.button.send",1,"btn","btn-primary",3,"click","disabled"],["bindLabel","actuator","appendTo","body","formControlName","action",3,"change","items","multiple","closeOnSelect","searchable","placeholder"],["appendTo","body","formControlName","type",3,"items","multiple","closeOnSelect","searchable","placeholder"],[3,"colorPickerChange","cpToggle","cpDialogDisplay","colorPicker","cpOutputFormat"],["type","text","formControlName","effect",1,"w-100","form-control",3,"placeholder"],["translate","tools.debugcommand.effect.error",4,"ngIf"],["translate","tools.debugcommand.effect.error"],["type","number","min","0","formControlName","level",1,"w-100","form-control",3,"placeholder"],["translate","tools.debugcommand.level.error",4,"ngIf"],["translate","tools.debugcommand.level.error"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"ng-select",8),e.nI1(18,"translate"),e.bIt("change",function(s){return n.callCapabilities(s)}),e.EFF(19,"\n "),e.DNE(20,Ze,10,2,"ng-template",9),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.j41(24,"div",10),e.EFF(25,"\n "),e.j41(26,"button",11),e.bIt("click",function(){return n.form.reset(),n.capaSelected=null}),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.j41(30,"div",12),e.EFF(31,"\n "),e.j41(32,"div",7),e.EFF(33,"\n "),e.DNE(34,Je,3,7,"ng-select",13),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.k0s(),e.EFF(37,"\n "),e.j41(38,"div",12),e.EFF(39,"\n "),e.j41(40,"div",7),e.EFF(41,"\n "),e.DNE(42,Qe,3,7,"ng-select",14),e.EFF(43,"\n "),e.k0s(),e.EFF(44,"\n "),e.k0s(),e.EFF(45,"\n "),e.DNE(46,$e,10,6,"div",15),e.EFF(47,"\n "),e.DNE(48,tt,13,4,"div",15),e.EFF(49,"\n "),e.DNE(50,ot,13,4,"div",15),e.EFF(51,"\n "),e.k0s(),e.EFF(52,"\n "),e.k0s(),e.EFF(53,"\n "),e.j41(54,"div",16),e.EFF(55,"\n "),e.j41(56,"button",17),e.bIt("click",function(){return n.callAction()}),e.k0s(),e.EFF(57,"\n "),e.k0s(),e.EFF(58,"\n "),e.k0s(),e.EFF(59,"\n"),e.k0s(),e.EFF(60,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,13,"tools.debugcommand.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(18,15,"tools.debugcommand.device")),e.Y8G("items",n.routers)("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(17),e.Y8G("ngIf",n.form.get("deviceSelected").value&&n.capabilities),e.R7$(8),e.Y8G("ngIf",n.capaSelected&&n.capaSelected.Type),e.R7$(4),e.Y8G("ngIf",n.capaSelected&&n.testRGB),e.R7$(2),e.Y8G("ngIf",n.capaSelected&&"hex"===n.capaSelected.Value),e.R7$(2),e.Y8G("ngIf",n.capaSelected&&"int"===n.capaSelected.Value),e.R7$(6),e.Y8G("disabled",!n.form.valid))},dependencies:[h.bT,c.qT,c.me,c.Q0,c.BC,c.cb,c.VZ,c.j4,c.JD,I.vr,I.Uq,v.Mm,Be,v.D9]})}return i})();function rt(i,l){1&i&&e.nrm(0,"div",14)}function st(i,l){1&i&&e.nrm(0,"div",14)}let lt=(()=>{class i{toastr;apiService;formBuilder;translate;form;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnInit(){this.form=this.formBuilder.group({Command:[null,c.k0.required],payload:[null]})}putCommand(){this.apiService.putCommandRaw(this.form.value).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}static \u0275fac=function(o){return new(o||i)(e.rXU(D.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-raw-command"]],decls:50,vars:13,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.rawcommand-zigate.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["type","text","formControlName","Command",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigate.error",4,"ngIf"],[1,"row","mt-2"],["type","text","formControlName","payload",1,"w-100","form-control",3,"placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.rawcommand-zigate.button.send",1,"btn","btn-primary",3,"click","disabled"],["translate","tools.rawcommand-zigate.error"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"div"),e.EFF(18,"\n "),e.nrm(19,"input",8),e.nI1(20,"translate"),e.EFF(21,"\n "),e.DNE(22,rt,1,0,"div",9),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.j41(27,"div",10),e.EFF(28,"\n "),e.j41(29,"div",7),e.EFF(30,"\n "),e.j41(31,"div"),e.EFF(32,"\n "),e.nrm(33,"input",11),e.nI1(34,"translate"),e.EFF(35,"\n "),e.DNE(36,st,1,0,"div",9),e.EFF(37,"\n "),e.k0s(),e.EFF(38,"\n "),e.k0s(),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.j41(43,"div",12),e.EFF(44,"\n "),e.j41(45,"button",13),e.bIt("click",function(){return n.putCommand()}),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.k0s(),e.EFF(48,"\n"),e.k0s(),e.EFF(49,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,7,"tools.rawcommand-zigate.subtitle"),e.npT),e.R7$(11),e.FS9("placeholder",e.bMT(20,9,"tools.rawcommand-zigate.command")),e.R7$(3),e.Y8G("ngIf",n.form.controls.Command.dirty&&!n.form.controls.Command.valid),e.R7$(11),e.FS9("placeholder",e.bMT(34,11,"tools.rawcommand-zigate.payload")),e.R7$(3),e.Y8G("ngIf",n.form.controls.payload.dirty&&!n.form.controls.payload.valid),e.R7$(9),e.Y8G("disabled",!n.form.valid))},dependencies:[h.bT,c.qT,c.me,c.BC,c.cb,c.j4,c.JD,v.Mm,v.D9]})}return i})();function at(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId," ")}}let ct=(()=>{class i{toastr;apiService;formBuilder;translate;devices$;form;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}selectedCar;TrueFalse=[{id:!1,name:"False"},{id:!0,name:"True"}];ngOnInit(){this.form=this.formBuilder.group({ProfileId:["0104",c.k0.required],ClusterId:["0000",c.k0.required],TargetAddr:[null,c.k0.required],TargetEp:["01",c.k0.required],SourceEp:["01",c.k0.required],Sqn:["55",c.k0.required],Payload:[null,c.k0.required],GroupAddressFlag:[!1,c.k0.required],AckMode:[!1,c.k0.required]}),this.devices$=this.apiService.getZDeviceName()}putCommand(){this.apiService.putCommandRawZigpy(this.form.value).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}static \u0275fac=function(o){return new(o||i)(e.rXU(D.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-raw-command-zigpy"]],decls:118,vars:34,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.rawcommand-zigpy.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["bindLabel","ZDeviceName","bindValue","_NwkId","formControlName","TargetAddr",3,"items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[1,"row","mt-2"],["translate","tools.rawcommand-zigpy.groupaddressflag",1,"col-sm-3","col-form-label"],["bindLabel","name","bindValue","id","formControlName","GroupAddressFlag",3,"items"],["translate","tools.rawcommand-zigpy.ackmode",1,"col-sm-3","col-form-label"],["bindLabel","name","bindValue","id","formControlName","AckMode",3,"items"],["translate","tools.rawcommand-zigpy.profileid",1,"col-sm-3","col-form-label"],[1,"col-sm-2"],["type","text","formControlName","ProfileId",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.clusterid",1,"col-sm-3","col-form-label"],["type","text","formControlName","ClusterId",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.sourceep",1,"col-sm-3","col-form-label"],["type","text","formControlName","SourceEp",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.targetep",1,"col-sm-3","col-form-label"],["type","text","formControlName","TargetEp",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.sqn",1,"col-sm-3","col-form-label"],["type","text","formControlName","Sqn",1,"w-100","form-control",3,"placeholder"],[1,"col-sm"],["type","text","formControlName","Payload",1,"w-100","form-control",3,"placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.rawcommand-zigpy.button.send",1,"btn","btn-primary",3,"click","disabled"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"ng-select",8),e.nI1(18,"translate"),e.nI1(19,"async"),e.EFF(20,"\n "),e.DNE(21,at,10,2,"ng-template",9),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.j41(26,"div",10),e.EFF(27,"\n "),e.nrm(28,"label",11),e.EFF(29,"\n "),e.j41(30,"div",7),e.EFF(31,"\n "),e.j41(32,"ng-select",12),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.k0s(),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.j41(37,"div",10),e.EFF(38,"\n "),e.nrm(39,"label",13),e.EFF(40,"\n "),e.j41(41,"div",7),e.EFF(42,"\n "),e.j41(43,"ng-select",14),e.EFF(44," "),e.k0s(),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.j41(48,"div",10),e.EFF(49,"\n "),e.nrm(50,"label",15),e.EFF(51,"\n "),e.j41(52,"div",16),e.EFF(53,"\n "),e.nrm(54,"input",17),e.nI1(55,"translate"),e.EFF(56,"\n "),e.k0s(),e.EFF(57,"\n "),e.nrm(58,"label",18),e.EFF(59,"\n "),e.j41(60,"div",16),e.EFF(61,"\n "),e.nrm(62,"input",19),e.nI1(63,"translate"),e.EFF(64,"\n "),e.k0s(),e.EFF(65,"\n "),e.k0s(),e.EFF(66,"\n "),e.j41(67,"div",10),e.EFF(68,"\n "),e.nrm(69,"label",20),e.EFF(70,"\n "),e.j41(71,"div",16),e.EFF(72,"\n "),e.nrm(73,"input",21),e.nI1(74,"translate"),e.EFF(75,"\n "),e.k0s(),e.EFF(76,"\n "),e.nrm(77,"label",22),e.EFF(78,"\n "),e.j41(79,"div",16),e.EFF(80,"\n "),e.nrm(81,"input",23),e.nI1(82,"translate"),e.EFF(83,"\n "),e.k0s(),e.EFF(84,"\n "),e.k0s(),e.EFF(85,"\n "),e.j41(86,"div",10),e.EFF(87,"\n "),e.nrm(88,"label",24),e.EFF(89,"\n "),e.j41(90,"div",16),e.EFF(91,"\n "),e.j41(92,"div"),e.EFF(93,"\n "),e.nrm(94,"input",25),e.nI1(95,"translate"),e.EFF(96,"\n "),e.k0s(),e.EFF(97,"\n "),e.k0s(),e.EFF(98,"\n "),e.k0s(),e.EFF(99,"\n "),e.j41(100,"div",10),e.EFF(101,"\n "),e.j41(102,"div",26),e.EFF(103,"\n "),e.nrm(104,"input",27),e.nI1(105,"translate"),e.EFF(106,"\n "),e.k0s(),e.EFF(107,"\n "),e.k0s(),e.EFF(108,"\n "),e.k0s(),e.EFF(109,"\n "),e.k0s(),e.EFF(110,"\n "),e.j41(111,"div",28),e.EFF(112,"\n "),e.j41(113,"button",29),e.bIt("click",function(){return n.putCommand()}),e.k0s(),e.EFF(114,"\n "),e.k0s(),e.EFF(115,"\n "),e.k0s(),e.EFF(116,"\n"),e.k0s(),e.EFF(117,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,16,"tools.rawcommand-zigpy.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(18,18,"tools.rawcommand-zigpy.placeholder")),e.Y8G("items",e.bMT(19,20,n.devices$))("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(15),e.Y8G("items",n.TrueFalse),e.R7$(11),e.Y8G("items",n.TrueFalse),e.R7$(11),e.FS9("placeholder",e.bMT(55,22,"tools.rawcommand-zigpy.profileid")),e.R7$(8),e.FS9("placeholder",e.bMT(63,24,"tools.rawcommand-zigpy.clusterid")),e.R7$(11),e.FS9("placeholder",e.bMT(74,26,"tools.rawcommand-zigpy.sourceep")),e.R7$(8),e.FS9("placeholder",e.bMT(82,28,"tools.rawcommand-zigpy.targetep")),e.R7$(13),e.FS9("placeholder",e.bMT(95,30,"tools.rawcommand-zigpy.sqn")),e.R7$(10),e.FS9("placeholder",e.bMT(105,32,"tools.rawcommand-zigpy.payload")),e.R7$(9),e.Y8G("disabled",!n.form.valid))},dependencies:[c.qT,c.me,c.BC,c.cb,c.j4,c.JD,I.vr,I.Uq,v.Mm,h.Jj,v.D9]})}return i})();function pt(i,l){1&i&&e.nrm(0,"app-raw-command")}function dt(i,l){1&i&&e.nrm(0,"app-raw-command-zigpy")}let ut=(()=>{class i{plugin;ngOnInit(){setTimeout(()=>{this.plugin=JSON.parse(sessionStorage.getItem("plugin"))},500)}static \u0275fac=function(o){return new(o||i)};static \u0275cmp=e.VBU({type:i,selectors:[["app-command"]],decls:9,vars:2,consts:[[1,"row","row-cols-1","row-cols-xxl-3","row-cols-lg-2","row-cols-md-1","row-cols-sm-1","g-4"],[4,"ngIf"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.nrm(2,"app-debug-command"),e.EFF(3,"\n "),e.DNE(4,pt,1,0,"app-raw-command",1),e.EFF(5,"\n "),e.DNE(6,dt,1,0,"app-raw-command-zigpy",1),e.EFF(7,"\n"),e.k0s(),e.EFF(8,"\n")),2&o&&(e.R7$(4),e.Y8G("ngIf",!(null!=n.plugin&&n.plugin.Zigpy)),e.R7$(2),e.Y8G("ngIf",null==n.plugin?null:n.plugin.Zigpy))},dependencies:[h.bT,it,lt,ct]})}return i})();var gt=m(88652),ae=m(38852);function mt(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",5),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function ht(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",6),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function ft(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",7),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function vt(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",5),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function Ct(i,l){if(1&i&&(e.j41(0,"div",8),e.EFF(1,"\n "),e.nrm(2,"input",9),e.EFF(3,"\n "),e.nrm(4,"label",10),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("id",t.setting.Name),e.R7$(2),e.FS9("for",t.setting.Name),e.FS9("translate",t.setting.Name)}}let Ft=(()=>{class i{formBuilder;fgd;setting;advanced;constructor(t,o){this.formBuilder=t,this.fgd=o}ngOnInit(){let t;t=this.formBuilder.group("hex"===this.setting.DataType?{current:["",c.k0.compose([c.k0.required,c.k0.pattern("^[0-9A-Fa-f]+")])]}:"bool"===this.setting.DataType?{current:[]}:{current:["",c.k0.required]}),this.fgd.form.addControl(this.setting.Name,t);const o=""!==this.setting.current_value?this.setting.current_value:this.setting.default_value;this.fgd.form.get(this.setting.Name).get("current").patchValue(o)}static \u0275fac=function(o){return new(o||i)(e.rXU(c.ok),e.rXU(c.j4))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-setting"]],inputs:{setting:"setting",advanced:"advanced"},features:[e.Jv_([],[{provide:c.ZU,useExisting:c.j4}])],decls:13,vars:6,consts:[[3,"formGroupName"],["class","d-flex flex-row align-items-center flex-wrap mt-2",4,"ngIf"],["class","form-check form-check-inline mt-2",4,"ngIf"],[1,"d-flex","flex-row","align-items-center","flex-wrap","mt-2"],["for","current",1,"me-2",3,"translate"],["type","text","formControlName","current",1,"w-25","form-control"],["type","text","formControlName","current",1,"w-100","form-control"],["type","number","formControlName","current",1,"form-control","w-25"],[1,"form-check","form-check-inline","mt-2"],["formControlName","current","type","checkbox",1,"form-check-input",3,"id"],[1,"form-check-label",3,"for","translate"]],template:function(o,n){1&o&&(e.qex(0,0),e.EFF(1,"\n "),e.DNE(2,mt,6,1,"div",1),e.EFF(3,"\n "),e.DNE(4,ht,6,1,"div",1),e.EFF(5,"\n "),e.DNE(6,ft,6,1,"div",1),e.EFF(7,"\n "),e.DNE(8,vt,6,1,"div",1),e.EFF(9,"\n "),e.DNE(10,Ct,6,3,"div",2),e.EFF(11,"\n"),e.bVm(),e.EFF(12,"\n")),2&o&&(e.Y8G("formGroupName",n.setting.Name),e.R7$(2),e.Y8G("ngIf","str"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","path"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","int"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","hex"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","bool"===n.setting.DataType))},dependencies:[h.bT,c.me,c.Q0,c.Zm,c.BC,c.cb,c.JD,c.$R,v.Mm],styles:["was-validated[_ngcontent-%COMP%] .custom-control-input[_ngcontent-%COMP%]:valid ~ .custom-control-label[_ngcontent-%COMP%], .custom-control-input.is-valid[_ngcontent-%COMP%] ~ .custom-control-label[_ngcontent-%COMP%]{color:#000}"]})}return i})();const $=["contentRestart"];function _t(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function bt(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,_t,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit;e.R7$(2),e.Y8G("ngIf",!t.Advanced&&"bool"===t.DataType)}}function kt(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function Et(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,kt,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit;e.R7$(2),e.Y8G("ngIf",!t.Advanced&&"bool"!==t.DataType)}}function yt(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function xt(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,yt,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit,o=e.XpG(4);e.R7$(2),e.Y8G("ngIf",t.Advanced&&t.Advanced===o.advanced)}}function wt(i,l){if(1&i&&(e.j41(0,"div",21),e.EFF(1,"\n "),e.nrm(2,"div",22),e.EFF(3,"\n "),e.j41(4,"div",23),e.EFF(5,"\n "),e.j41(6,"div",24),e.EFF(7,"\n "),e.nrm(8,"p",25),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.j41(11,"div",24),e.EFF(12,"\n "),e.j41(13,"div",26),e.EFF(14,"\n "),e.DNE(15,bt,4,1,"ng-container",19),e.EFF(16,"\n "),e.k0s(),e.EFF(17,"\n "),e.j41(18,"div",27),e.EFF(19,"\n "),e.DNE(20,Et,4,1,"ng-container",19),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"div",27),e.EFF(24,"\n "),e.DNE(25,xt,4,1,"ng-container",19),e.EFF(26,"\n "),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.k0s()),2&i){const t=e.XpG().$implicit,o=e.XpG(2);e.R7$(2),e.Y8G("innerHTML",o.getTranslation("setting.header.",t._Theme),e.npT),e.R7$(6),e.Y8G("innerHTML",o.getTranslation("setting.subtitle.",t._Theme),e.npT),e.R7$(7),e.Y8G("ngForOf",t.ListOfSettings),e.R7$(5),e.Y8G("ngForOf",t.ListOfSettings),e.R7$(5),e.Y8G("ngForOf",t.ListOfSettings)}}function jt(i,l){if(1&i&&(e.j41(0,"div"),e.EFF(1,"\n "),e.DNE(2,wt,30,5,"div",20),e.EFF(3,"\n "),e.k0s()),2&i){const t=l.$implicit,o=e.XpG(2);e.R7$(2),e.Y8G("ngIf",o.hasBasicSettings(t.ListOfSettings))}}function At(i,l){if(1&i){const t=e.RV6();e.j41(0,"form",4),e.EFF(1,"\n "),e.j41(2,"fieldset",5),e.EFF(3,"\n "),e.j41(4,"legend"),e.EFF(5,"\n "),e.j41(6,"div",6),e.EFF(7,"\n "),e.nrm(8,"h5",7),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",8),e.EFF(12,"\n "),e.j41(13,"div",9),e.EFF(14,"\n "),e.j41(15,"div",10),e.EFF(16,"\n "),e.j41(17,"button",11),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.updateSettings())}),e.k0s(),e.EFF(18,"\n "),e.k0s(),e.EFF(19,"\n "),e.j41(20,"div",12),e.EFF(21,"\n "),e.j41(22,"button",13),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.reinitSettings())}),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.j41(25,"div",14),e.EFF(26,"\n "),e.j41(27,"input",15),e.bIt("click",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.advancedSettings(n))}),e.k0s(),e.EFF(28,"\n "),e.nrm(29,"label",16),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n "),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.k0s(),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.j41(37,"div",17),e.EFF(38,"\n "),e.j41(39,"div",18),e.EFF(40,"\n "),e.DNE(41,jt,4,1,"div",19),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.k0s(),e.EFF(44,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("formGroup",t.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,5,"tools.debugsetting.help.legend"),e.npT),e.R7$(9),e.Y8G("disabled",!t.form.valid),e.R7$(10),e.Y8G("checked",t.advanced),e.R7$(14),e.Y8G("ngForOf",t.settings)}}function Tt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",31),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",33),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",35),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}function It(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",36),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",37),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",38),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}function Rt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",39),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",40),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",41),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}let St=(()=>{class i{modalService;apiService;formBuilder;toastr;headerService;translate;contentRestart;contentReset;contentErase;form;settings;advanced=!1;constructor(t,o,n,r,s,a){this.modalService=t,this.apiService=o,this.formBuilder=n,this.toastr=r,this.headerService=s,this.translate=a}ngOnInit(){this.form=this.formBuilder.group({}),this.apiService.getSettingsDebug().subscribe(t=>{this.settings=t,this.settings[0].ListOfSettings.sort((o,n)=>o.Name.localeCompare(n.Name))})}reinitSettings(){this.settings.forEach(t=>{const o=[];t.ListOfSettings.forEach(n=>{n.current_value=n.default_value,o.push(Object.assign({},n))}),t.ListOfSettings=o}),this.settings=[...this.settings]}advancedSettings(t){this.advanced=!!t.currentTarget.checked}updateSettings(){this.form.invalid?this.form.markAsTouched():(Object.keys(this.form.value).forEach(t=>{!0===this.form.value[t].current?this.form.value[t].current=1:!1===this.form.value[t].current&&(this.form.value[t].current=0)}),this.apiService.putSettingsDebug(this.form.value).subscribe(()=>{this.form.markAsPristine(),this.toastr.success(this.translate.instant("api.global.succes.saved.notify")),this.apiService.getSettingsDebug().subscribe(t=>{this.settings=t,this.settings[0].ListOfSettings.sort((o,n)=>o.Name.localeCompare(n.Name))}),this.apiService.getRestartNeeded().subscribe(t=>{1===t.RestartNeeded?(this.headerService.setRestart(!0),this.open(this.contentRestart)):2===t.RestartNeeded?this.open(this.contentReset):3===t.RestartNeeded&&this.open(this.contentErase)})}))}open(t){this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then()}hasBasicSettings(t){return!!this.advanced||t.filter(o=>!1===o.Advanced).length>0}getTranslation(t,o){return this.translate.instant(t.concat(o))}static \u0275fac=function(o){return new(o||i)(e.rXU(gt.Bq),e.rXU(A.G),e.rXU(c.ok),e.rXU(D.tw),e.rXU(ae.d),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-settings"]],viewQuery:function(o,n){if(1&o&&(e.GBs($,5),e.GBs($,5),e.GBs($,5)),2&o){let r;e.mGM(r=e.lsd())&&(n.contentRestart=r.first),e.mGM(r=e.lsd())&&(n.contentReset=r.first),e.mGM(r=e.lsd())&&(n.contentErase=r.first)}},decls:11,vars:1,consts:[["contentRestart",""],["contentReset",""],["contentErase",""],[3,"formGroup",4,"ngIf"],[3,"formGroup"],[1,"h-100"],[1,"row"],[1,"col-sm-8",3,"innerHTML"],[1,"col-sm-4"],[1,"d-flex","flex-row-reverse","align-items-center"],[1,"p-2"],["translate","tools.debugsetting.validate.button",1,"btn","btn-primary",3,"click","disabled"],[1,"p-2","ms-3"],["translate","tools.debugsetting.reinit.button",1,"btn","btn-secondary",3,"click"],[1,"switch","switch-sm","me-2","pr-2","float-right"],["type","checkbox","id","switch-advanced",1,"switch",3,"click","checked"],["for","switch-advanced","translate","tools.debugsetting.advanced.button",1,"mb-0"],[1,"row","row-cols-1","row-cols-sm-1","g-4"],[1,"col"],[4,"ngFor","ngForOf"],["class","card",4,"ngIf"],[1,"card"],[1,"card-header","fw-bold",3,"innerHTML"],[1,"card-body"],[1,"card-text"],[3,"innerHTML"],[1,"row","row-cols-1","row-cols-xl-6","row-cols-md-3","row-cols-sm-1","align-items-center"],[1,"row","row-cols-1","row-cols-xl-6","row-cols-md-3","row-cols-sm-1","align-items-center","mt-2"],[3,"setting","advanced",4,"ngIf"],[3,"setting","advanced"],[1,"modal-header"],["id","modal-basic-title","translate","setting.reloadplugin.alert.title",1,"modal-title"],["type","button","aria-label","Close",1,"btn-close",3,"click"],["translate","setting.reloadplugin.alert.subject",1,"modal-body"],[1,"modal-footer"],["type","button","translate","setting.reloadplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","setting.resetplugin.alert.title",1,"modal-title"],["translate","setting.resetplugin.alert.subject",1,"modal-body"],["type","button","translate","setting.resetplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","setting.eraseplugin.alert.title",1,"modal-title"],["translate","setting.eraseplugin.alert.subject",1,"modal-body"],["type","button","translate","setting.eraseplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"]],template:function(o,n){1&o&&(e.DNE(0,At,45,7,"form",3),e.EFF(1,"\n\n"),e.DNE(2,Tt,15,0,"ng-template",null,0,e.C5r),e.EFF(4,"\n\n"),e.DNE(5,It,15,0,"ng-template",null,1,e.C5r),e.EFF(7,"\n\n"),e.DNE(8,Rt,15,0,"ng-template",null,2,e.C5r),e.EFF(10,"\n")),2&o&&e.Y8G("ngIf",n.settings)},dependencies:[h.Sq,h.bT,c.qT,c.cb,c.j4,v.Mm,Ft,v.D9],styles:[".btn-secondary[_ngcontent-%COMP%]{--bs-btn-color: white}"]})}return i})();var ce=m(70980);function pe(i,l){const t=new h.vh("en-US");if("LastSeen"===i)return t.transform(1e3*l,"dd/MM/yyyy HH:mm:ss");if(["TimeStamps","TimeStamp","Stamp","Time","StartTime","BatteryUpdateTime","TargetTime"].indexOf(i)>-1){if(l>0){let n=1e3*l;return n=Number(n.toFixed(0)),t.transform(n,"dd/MM/yyyy HH:mm:ss")}return l}return l}function Bt(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",4),e.EFF(1,"\n "),e.j41(2,"button",5),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.export(n.json))}),e.k0s(),e.EFF(3,"\n\n "),e.nrm(4,"ngx-json-viewer",6),e.EFF(5,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("hidden",t.isLoading),e.R7$(4),e.Y8G("expanded",!1)("json",t.json)}}let Vt=(()=>{class i{apiService;headerService;fileSaverService;json=null;isLoading=!1;constructor(t,o,n){this.apiService=t,this.headerService=o,this.fileSaverService=n}onClick(t){let o;this.json=null,"log-error-history"===t&&(o=this.apiService.getLogErrorHistory(),this.headerService.setError(!1)),"clear-error-history"===t&&(o=this.apiService.clearLogErrorHistory(),this.headerService.setError(!1)),o&&o.pipe((0,ce.j)(()=>{this.isLoading=!1})).subscribe(n=>{this.callbackservice(n)})}callbackservice(t){const o=JSON.stringify(t);this.json=JSON.parse(o,pe)}export(t){const o="errors.json",n=this.fileSaverService.genType(o),r=new Blob([JSON.stringify(t)],{type:n});this.fileSaverService.save(r,o)}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(ae.d),e.rXU(re))};static \u0275cmp=e.VBU({type:i,selectors:[["app-error"]],decls:9,vars:1,consts:[[1,"row","d-flex","ms-2","gap-2"],["translate","tools.error.log-history.button",1,"col-xl-2","col-lg-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.error.log-history.clear",1,"col-xl-2","col-lg-4","col-sm-5","btn","btn-primary",3,"click"],["class","row ms-2 mt-2",3,"hidden",4,"ngIf"],[1,"row","ms-2","mt-2",3,"hidden"],["translate","tools.tools.export",1,"col-lg-1","mb-2","btn","btn-primary",3,"click"],[3,"expanded","json"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"button",1),e.bIt("click",function(){return n.onClick("log-error-history")}),e.k0s(),e.EFF(3,"\n "),e.j41(4,"button",2),e.bIt("click",function(){return n.onClick("clear-error-history")}),e.k0s(),e.EFF(5,"\n"),e.k0s(),e.EFF(6,"\n"),e.DNE(7,Bt,6,3,"div",3),e.EFF(8,"\n")),2&o&&(e.R7$(7),e.Y8G("ngIf",n.json))},dependencies:[h.bT,v.Mm,se]})}return i})();var Dt=m(34402),ee=m(46247),Pt=m(5779),Mt=m(22242);const Gt=()=>[10,25,50];function Nt(i,l){1&i&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"th",5),e.EFF(4),e.nI1(5,"translate"),e.k0s(),e.EFF(6,"\n "),e.j41(7,"th",6),e.EFF(8),e.nI1(9,"translate"),e.k0s(),e.EFF(10,"\n "),e.j41(11,"th",7),e.EFF(12),e.nI1(13,"translate"),e.k0s(),e.EFF(14,"\n "),e.j41(15,"th",7),e.EFF(16),e.nI1(17,"translate"),e.k0s(),e.EFF(18,"\n "),e.j41(19,"th",7),e.EFF(20),e.nI1(21,"translate"),e.k0s(),e.EFF(22,"\n "),e.j41(23,"th",7),e.EFF(24),e.nI1(25,"translate"),e.k0s(),e.EFF(26,"\n "),e.j41(27,"th",8),e.EFF(28),e.nI1(29,"translate"),e.k0s(),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n ")),2&i&&(e.R7$(4),e.JRh(e.bMT(5,7,"tools.reporting.configure.clusterId.column")),e.R7$(4),e.JRh(e.bMT(9,9,"tools.reporting.configure.attributeId.column")),e.R7$(4),e.JRh(e.bMT(13,11,"tools.reporting.configure.dataType.column")),e.R7$(4),e.JRh(e.bMT(17,13,"tools.reporting.configure.timeout.column")),e.R7$(4),e.JRh(e.bMT(21,15,"tools.reporting.configure.minInterval.column")),e.R7$(4),e.JRh(e.bMT(25,17,"tools.reporting.configure.maxInterval.column")),e.R7$(4),e.JRh(e.bMT(29,19,"tools.reporting.configure.change.column")))}function Ot(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MinInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.minInterval)}}function Xt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MinInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.minInterval)}}function Yt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MaxInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.maxInterval)}}function qt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MaxInterval",r))}),e.k0s(),e.EFF(2," ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.maxInterval)}}function Ht(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG(2).$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"Change",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG(2).$implicit;e.R7$(),e.Y8G("value",t.change)}}function zt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG(2).$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"Change",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG(2).$implicit;e.R7$(),e.Y8G("value",t.change)}}function Ut(i,l){1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,Ht,3,1,"ng-template",10),e.EFF(3,"\n "),e.DNE(4,zt,3,1,"ng-template",11),e.EFF(5,"\n "),e.bVm())}function Kt(i,l){if(1&i&&e.EFF(0),2&i){const t=e.XpG().$implicit;e.JRh(t.change)}}function Lt(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td"),e.EFF(4),e.k0s(),e.EFF(5,"\n "),e.j41(6,"td"),e.EFF(7),e.k0s(),e.EFF(8,"\n "),e.j41(9,"td"),e.EFF(10),e.k0s(),e.EFF(11,"\n "),e.j41(12,"td"),e.EFF(13),e.k0s(),e.EFF(14,"\n "),e.j41(15,"td",9),e.EFF(16,"\n "),e.j41(17,"p-cellEditor"),e.EFF(18,"\n "),e.DNE(19,Ot,3,1,"ng-template",10),e.EFF(20,"\n "),e.DNE(21,Xt,3,1,"ng-template",11),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.j41(25,"td",12),e.EFF(26,"\n "),e.j41(27,"p-cellEditor"),e.EFF(28,"\n "),e.DNE(29,Yt,3,1,"ng-template",10),e.EFF(30,"\n "),e.DNE(31,qt,3,1,"ng-template",11),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n "),e.j41(34,"td",13),e.EFF(35,"\n "),e.j41(36,"p-cellEditor"),e.EFF(37,"\n "),e.DNE(38,Ut,6,0,"ng-container",14),e.EFF(39,"\n "),e.DNE(40,Kt,1,1,"ng-template",null,1,e.C5r),e.k0s(),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.k0s()),2&i){const t=l.$implicit,o=e.sdS(41),n=e.XpG();e.R7$(4),e.JRh(t.clusterId),e.R7$(3),e.JRh(t.attributeId),e.R7$(3),e.JRh(t.dataType),e.R7$(3),e.JRh(t.timeOut),e.R7$(2),e.Y8G("pEditableColumn",t.minInterval),e.R7$(10),e.Y8G("pEditableColumn",t.maxInterval),e.R7$(9),e.Y8G("pEditableColumn",t.change),e.R7$(4),e.Y8G("ngIf",n.isEditable(t))("ngIfElse",o)}}let Wt=(()=>{class i{toastr;apiService;formBuilder;translate;clusters;clustersChange=new e.bkB;clustersToDisplay=[];datatypeConvertor=[{type:"10",longueur:"0",editable:!1},{type:"20",longueur:"0",editable:!0},{type:"21",longueur:"00",editable:!0},{type:"22",longueur:"000",editable:!0},{type:"23",longueur:"0000",editable:!0},{type:"24",longueur:"00000",editable:!0},{type:"25",longueur:"000000",editable:!0},{type:"26",longueur:"0000000",editable:!0},{type:"27",longueur:"00000000",editable:!0},{type:"28",longueur:"0",editable:!0},{type:"29",longueur:"00",editable:!0},{type:"2a",longueur:"000",editable:!0},{type:"2b",longueur:"0000",editable:!0},{type:"2c",longueur:"00000",editable:!0},{type:"2d",longueur:"000000",editable:!0},{type:"2e",longueur:"0000000",editable:!0},{type:"2f",longueur:"00000000",editable:!0},{type:"38",longueur:"00",editable:!0},{type:"39",longueur:"0000",editable:!0},{type:"3a",longueur:"00000000",editable:!0},{type:"e0",longueur:"0000",editable:!0},{type:"e1",longueur:"0000",editable:!0},{type:"e2",longueur:"0000",editable:!0}];constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnChanges(t){t.clusters.currentValue&&this.formatClusters(t.clusters.currentValue)}formatClusters(t){this.clustersToDisplay=[],t.forEach(o=>{o.Attributes.forEach(n=>{n.Infos.forEach(r=>{const s=new Dt.E0;s.clusterId=o.ClusterId,s.attributeId=n.Attribute,s.change=parseInt(r.Change,16).toString(),s.dataType=r.DataType,s.maxInterval=parseInt(r.MaxInterval,16).toString(),s.minInterval=parseInt(r.MinInterval,16).toString(),s.timeOut=parseInt(r.TimeOut,16).toString(),this.clustersToDisplay.push(s)})})})}updateValue(t,o,n){const r=t.target.value,s=this.clusters.find(a=>a.ClusterId===n.clusterId).Attributes.find(a=>a.Attribute===n.attributeId).Infos[0];if(!this.controlerValue(Number(r),o,s)){if("Change"===o){const a=this.datatypeConvertor.find(d=>d.type===s.DataType);s[o]=(a.longueur+Number(r).toString(16).toUpperCase()).slice(-a.longueur.length)}else s[o]=Number(r).toString(16).toUpperCase();this.formatClusters(this.clusters),this.clustersChange.emit(this.clusters)}}controlerValue(t,o,n){let r=!1;if(isNaN(t))r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.hexa.error"));else if("Change"!==o&&Number(t)>65535)r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error"));else if("Change"===o){const s=this.datatypeConvertor.find(d=>d.type===n.DataType),a=s.longueur.split("0").join("F");Number(t)>parseInt(a,16)&&(r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error"))),"10"===s.type&&Number(t)>1&&(r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error")))}return r}isEditable(t){const o=this.datatypeConvertor.find(n=>n.type===t.dataType);return o&&o.editable}static \u0275fac=function(o){return new(o||i)(e.rXU(D.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-configure-cluster-reporting"]],inputs:{clusters:"clusters"},outputs:{clustersChange:"clustersChange"},features:[e.OA$],decls:9,vars:11,consts:[["dt1",""],["notEditable",""],["responsiveLayout","scroll","stateStorage","local","stateKey","cluster",3,"rowHover","showCurrentPageReport","currentPageReportTemplate","rowsPerPageOptions","value","rows","paginator","scrollable"],["pTemplate","header"],["pTemplate","body"],[2,"width","15rem"],[2,"width","7rem"],[2,"width","5rem"],[2,"width","3rem"],["pEditableColumnField","minInterval",3,"pEditableColumn"],["pTemplate","input"],["pTemplate","output"],["pEditableColumnField","maxInterval",3,"pEditableColumn"],["pEditableColumnField","change",3,"pEditableColumn"],[4,"ngIf","ngIfElse"],["pInputText","","type","text",3,"change","value"]],template:function(o,n){1&o&&(e.j41(0,"p-table",2,0),e.nI1(2,"translate"),e.EFF(3,"\n "),e.DNE(4,Nt,32,21,"ng-template",3),e.EFF(5,"\n "),e.DNE(6,Lt,44,9,"ng-template",4),e.EFF(7,"\n"),e.k0s(),e.EFF(8,"\n")),2&o&&(e.FS9("currentPageReportTemplate",e.bMT(2,8,"TOTAL")),e.Y8G("rowHover",!0)("showCurrentPageReport",!0)("rowsPerPageOptions",e.lJ4(10,Gt))("value",n.clustersToDisplay)("rows",10)("paginator",!0)("scrollable",!0))},dependencies:[h.bT,ee.XI,Pt.Ei,ee.hp,ee.c5,Mt.S,v.D9]})}return i})();function Zt(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId,"")}}function Jt(i,l){if(1&i){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"app-configure-cluster-reporting",16),e.bIt("clustersChange",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onClustersChange(n))}),e.k0s(),e.EFF(3,"\n "),e.bVm()}if(2&i){const t=l.ngIf;e.R7$(2),e.Y8G("clusters",t)}}let Qt=(()=>{class i{toastr;apiService;translate;devices$;clusters$;deviceSelected;form;clustersToSave;permitToValidate=!1;constructor(t,o,n){this.toastr=t,this.apiService=o,this.translate=n}ngOnInit(){this.devices$=this.apiService.getZDevices()}getConfiguration(t){this.deviceSelected=null,t&&(this.deviceSelected=t._NwkId,this.clusters$=this.apiService.getConfigureReporting(this.deviceSelected))}putConfiguration(){this.apiService.putConfigureReporting(this.deviceSelected,this.clustersToSave).subscribe(()=>{this.permitToValidate=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}resetConfiguration(){this.apiService.deleteConfigureReporting(this.deviceSelected).subscribe(()=>{this.permitToValidate=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}triggerConfiguration(){this.apiService.getTriggerConfigureReporting(this.deviceSelected).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}onClustersChange(t){this.permitToValidate=!1,this.clustersToSave=null,t&&(this.permitToValidate=!0,this.clustersToSave=t)}static \u0275fac=function(o){return new(o||i)(e.rXU(D.tw),e.rXU(A.G),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-configure-reporting"]],decls:50,vars:30,consts:[[1,"col"],[1,"card"],[1,"card-header","d-flex"],[1,"col","fw-bold","justify-content-start"],[1,"col","d-flex","justify-content-end"],[1,"btn","btn-danger",3,"click","disabled","translate"],[1,"btn","btn-secondary","ms-3",3,"click","disabled","translate"],[1,"btn","btn-primary","ms-3",3,"click","disabled","translate"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-3","mb-2"],["bindLabel","ZDeviceName","appendTo","body",3,"change","clear","items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[4,"ngIf"],[3,"clustersChange","clusters"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.j41(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7),e.nI1(8,"translate"),e.k0s(),e.EFF(9,"\n "),e.j41(10,"div",4),e.EFF(11,"\n "),e.j41(12,"button",5),e.nI1(13,"translate"),e.bIt("click",function(){return n.resetConfiguration()}),e.k0s(),e.EFF(14,"\n "),e.j41(15,"button",6),e.nI1(16,"translate"),e.bIt("click",function(){return n.triggerConfiguration()}),e.k0s(),e.EFF(17,"\n "),e.j41(18,"button",7),e.nI1(19,"translate"),e.bIt("click",function(){return n.putConfiguration()}),e.k0s(),e.EFF(20,"\n "),e.k0s(),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"div",8),e.EFF(24,"\n "),e.nrm(25,"p",9),e.nI1(26,"translate"),e.EFF(27,"\n "),e.j41(28,"div",10),e.EFF(29,"\n "),e.j41(30,"div",11),e.EFF(31,"\n "),e.j41(32,"div",12),e.EFF(33,"\n "),e.j41(34,"ng-select",13),e.nI1(35,"translate"),e.nI1(36,"async"),e.bIt("change",function(s){return n.getConfiguration(s)})("clear",function(){return n.deviceSelected=null,n.permitToValidate=!1}),e.EFF(37,"\n "),e.DNE(38,Zt,10,2,"ng-template",14),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.DNE(43,Jt,4,1,"ng-container",15),e.nI1(44,"async"),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.k0s(),e.EFF(48,"\n"),e.k0s(),e.EFF(49,"\n")),2&o&&(e.R7$(7),e.JRh(e.bMT(8,14,"tools.reporting.configure.title")),e.R7$(5),e.FS9("translate",e.bMT(13,16,"tools.reporting.configure.reset.button")),e.Y8G("disabled",!n.deviceSelected),e.R7$(3),e.FS9("translate",e.bMT(16,18,"tools.reporting.configure.trigger.button")),e.Y8G("disabled",!n.deviceSelected),e.R7$(3),e.FS9("translate",e.bMT(19,20,"tools.reporting.configure.validate.button")),e.Y8G("disabled",!n.permitToValidate),e.R7$(7),e.Y8G("innerHTML",e.bMT(26,22,"tools.reporting.configure.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(35,24,"tools.reporting.configure.device")),e.Y8G("items",e.bMT(36,26,n.devices$))("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(9),e.Y8G("ngIf",e.bMT(44,28,n.deviceSelected&&n.clusters$)))},dependencies:[h.bT,I.vr,I.Uq,v.Mm,Wt,h.Jj,v.D9]})}return i})(),$t=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275cmp=e.VBU({type:i,selectors:[["app-reporting"]],decls:5,vars:0,consts:[[1,"row","row-cols-1","g-4"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.nrm(2,"app-configure-reporting"),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n"))},dependencies:[Qt]})}return i})();var en=m(27468);function tn(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",15),e.bIt("click",function(){const n=e.eBV(t).ngIf,r=e.XpG();return e.Njj(r.download(n))}),e.k0s()}}function nn(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",16),e.EFF(1,"\n "),e.j41(2,"button",17),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.export(n.json))}),e.k0s(),e.EFF(3,"\n\n "),e.nrm(4,"ngx-json-viewer",18),e.EFF(5,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("hidden",t.isLoading),e.R7$(4),e.Y8G("expanded",!1)("json",t.json)}}let on=(()=>{class i{apiService;fileSaverService;json=null;isLoading=!1;logFile$;constructor(t,o){this.apiService=t,this.fileSaverService=o}ngOnInit(){this.logFile$=this.apiService.getLog()}onClick(t){let o;this.json=null,"devices"===t&&(o=this.apiService.getDevices()),"zdevices"===t&&(o=this.apiService.getZDevices()),"zgroups"===t&&(o=this.apiService.getZGroups()),"zdevice-raw"===t&&(o=this.apiService.getRawZDevices()),"infos"===t&&(o=this.apiService.getPlugin()),"coordinator"===t&&(o=this.apiService.getCoordinator()),"plugin-health"===t&&(o=this.apiService.getPluginhealth()),"zgroup-list-available-device"===t&&(o=this.apiService.getZGroupDevicesAvalaible()),"settings"===t&&(o=this.apiService.getSettings()),"plugin-stat"===t&&(o=this.apiService.getPluginStats()),"zdevice-name"===t&&(o=this.apiService.getZDeviceName()),"domoticz-env"===t&&(o=this.apiService.getDomoticzEnv()),"battery-state"===t&&(o=this.apiService.getBatteryState()),o&&o.pipe((0,ce.j)(()=>{this.isLoading=!1})).subscribe(n=>{this.callbackservice(n)})}getAllNonOptimizedDevice(){this.json=null,this.apiService.getZDeviceName().subscribe(t=>{const o=t.filter(n=>!n.CertifiedDevice).map(n=>this.getNonOptimizedDevice(n._NwkId));(0,en.p)(o).subscribe(n=>this.callbackservice(n))})}getNonOptimizedDevice(t){return this.apiService.getNonOptimizedDevice(t)}download(t){const o=t.Filename;this.apiService.downloadLog(t.URL).subscribe(n=>{this.fileSaverService.save(n.body,o)})}callbackservice(t){const o=JSON.stringify(t);this.json=JSON.parse(o,pe)}export(t){const o="export.json",n=this.fileSaverService.genType(o),r=new Blob([JSON.stringify(t)],{type:n});this.fileSaverService.save(r,o)}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(re))};static \u0275cmp=e.VBU({type:i,selectors:[["app-tools"]],decls:32,vars:4,consts:[[1,"row","d-flex","ms-2","gap-2"],["translate","tools.tools.zdevice-raw.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.non-optimized.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zgroup.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.plugin-stat.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.coordinator.infos.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["class","col-lg-2 col-md-4 col-sm-5 btn btn-primary","translate","tools.tools.log.button",3,"click",4,"ngIf"],["translate","tools.tools.infos.plugin.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.plugin-health.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.settings.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.domoticz-env.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.battery-state.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zdevice-name.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zgroup-list-available-device.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["class","row ms-2 mt-2",3,"hidden",4,"ngIf"],["translate","tools.tools.log.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],[1,"row","ms-2","mt-2",3,"hidden"],["translate","tools.tools.export",1,"col-lg-1","mb-2","btn","btn-primary",3,"click"],[3,"expanded","json"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"button",1),e.bIt("click",function(){return n.onClick("zdevice-raw")}),e.k0s(),e.EFF(3,"\n "),e.j41(4,"button",2),e.bIt("click",function(){return n.getAllNonOptimizedDevice()}),e.k0s(),e.EFF(5,"\n "),e.j41(6,"button",3),e.bIt("click",function(){return n.onClick("zgroups")}),e.k0s(),e.EFF(7,"\n "),e.j41(8,"button",4),e.bIt("click",function(){return n.onClick("plugin-stat")}),e.k0s(),e.EFF(9,"\n "),e.j41(10,"button",5),e.bIt("click",function(){return n.onClick("coordinator")}),e.k0s(),e.EFF(11,"\n "),e.DNE(12,tn,1,0,"button",6),e.nI1(13,"async"),e.EFF(14,"\n "),e.j41(15,"button",7),e.bIt("click",function(){return n.onClick("infos")}),e.k0s(),e.EFF(16,"\n "),e.j41(17,"button",8),e.bIt("click",function(){return n.onClick("plugin-health")}),e.k0s(),e.EFF(18,"\n "),e.j41(19,"button",9),e.bIt("click",function(){return n.onClick("settings")}),e.k0s(),e.EFF(20,"\n "),e.j41(21,"button",10),e.bIt("click",function(){return n.onClick("domoticz-env")}),e.k0s(),e.EFF(22,"\n "),e.j41(23,"button",11),e.bIt("click",function(){return n.onClick("battery-state")}),e.k0s(),e.EFF(24,"\n "),e.j41(25,"button",12),e.bIt("click",function(){return n.onClick("zdevice-name")}),e.k0s(),e.EFF(26,"\n "),e.j41(27,"button",13),e.bIt("click",function(){return n.onClick("zgroup-list-available-device")}),e.k0s(),e.EFF(28,"\n"),e.k0s(),e.EFF(29,"\n"),e.DNE(30,nn,6,3,"div",14),e.EFF(31,"\n")),2&o&&(e.R7$(12),e.Y8G("ngIf",e.bMT(13,2,n.logFile$)),e.R7$(18),e.Y8G("ngIf",n.json))},dependencies:[h.bT,v.Mm,se,h.Jj]})}return i})();const rn=[{path:"command",component:ut,data:{title:(0,V.o6)("command")}},{path:"debug",component:St,data:{title:(0,V.o6)("debug")}},{path:"binding",component:We,data:{title:(0,V.o6)("binding")}},{path:"link",component:on,data:{title:(0,V.o6)("tools")}},{path:"error",component:Vt,data:{title:(0,V.o6)("error")}},{path:"configure",component:$t,data:{title:(0,V.o6)("configure")}}];let sn=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({imports:[le.iI.forChild(rn),le.iI]})}return i})(),ln=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({imports:[q.G,sn,qe,Pe,Ve]})}return i})()},2578:function(W,Y){var m,e;void 0!==(e="function"==typeof(m=function(){"use strict";function R(u,g,x){var f=new XMLHttpRequest;f.open("GET",u),f.responseType="blob",f.onload=function(){M(f.response,g,x)},f.onerror=function(){console.error("could not download file")},f.send()}function H(u){var g=new XMLHttpRequest;g.open("HEAD",u,!1);try{g.send()}catch{}return 200<=g.status&&299>=g.status}function P(u){try{u.dispatchEvent(new MouseEvent("click"))}catch{var g=document.createEvent("MouseEvents");g.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),u.dispatchEvent(g)}}var y="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,z=y.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),M=y.saveAs||("object"!=typeof window||window!==y?function(){}:"download"in HTMLAnchorElement.prototype&&!z?function(u,g,x){var f=y.URL||y.webkitURL,b=document.createElement("a");b.download=g=g||u.name||"download",b.rel="noopener","string"==typeof u?(b.href=u,b.origin===location.origin?P(b):H(b.href)?R(u,g,x):P(b,b.target="_blank")):(b.href=f.createObjectURL(u),setTimeout(function(){f.revokeObjectURL(b.href)},4e4),setTimeout(function(){P(b)},0))}:"msSaveOrOpenBlob"in navigator?function(u,g,x){if(g=g||u.name||"download","string"!=typeof u)navigator.msSaveOrOpenBlob(function h(u,g){return typeof g>"u"?g={autoBom:!1}:"object"!=typeof g&&(console.warn("Deprecated: Expected third argument to be a object"),g={autoBom:!g}),g.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(u.type)?new Blob(["\ufeff",u],{type:u.type}):u}(u,x),g);else if(H(u))R(u,g,x);else{var f=document.createElement("a");f.href=u,f.target="_blank",setTimeout(function(){P(f)})}}:function(u,g,x,f){if((f=f||open("","_blank"))&&(f.document.title=f.document.body.innerText="downloading..."),"string"==typeof u)return R(u,g,x);var b="application/octet-stream"===u.type,Z=/constructor/i.test(y.HTMLElement)||y.safari,U=/CriOS\/[\d]+/.test(navigator.userAgent);if((U||b&&Z||z)&&typeof FileReader<"u"){var G=new FileReader;G.onloadend=function(){var S=G.result;S=U?S:S.replace(/^data:[^;]*;/,"data:attachment/file;"),f?f.location.href=S:location=S,f=null},G.readAsDataURL(u)}else{var K=y.URL||y.webkitURL,N=K.createObjectURL(u);f?f.location=N:location.href=N,f=null,setTimeout(function(){K.revokeObjectURL(N)},4e4)}});y.saveAs=M.saveAs=M,W.exports=M})?m.apply(Y,[]):m)&&(W.exports=e)}}]); \ No newline at end of file +(self.webpackChunkz4d_plugin=self.webpackChunkz4d_plugin||[]).push([[846],{2846:(W,Y,m)=>{"use strict";m.r(Y),m.d(Y,{ToolsModule:()=>ln});var q=m(93887),e=m(54438),h=m(60177);const S=["dialogPopup"],H=["hueSlider"],D=["alphaSlider"];function y(i,l){if(1&i&&e.nrm(0,"div"),2&i){const t=e.XpG();e.ZvI("arrow arrow-",t.cpUsePosition,""),e.xc7("left",t.cpArrowPosition)("top",t.arrowTop,"px")}}function z(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",28),e.bIt("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onColorChange(n))})("dragStart",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onDragStart("saturation-lightness"))})("dragEnd",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onDragEnd("saturation-lightness"))}),e.nrm(1,"div",16),e.k0s()}if(2&i){const t=e.XpG();e.xc7("background-color",t.hueSliderColor),e.Y8G("rgX",1)("rgY",1),e.R7$(),e.xc7("top",null==t.slider?null:t.slider.v,"px")("left",null==t.slider?null:t.slider.s,"px")}}function M(i,l){1&i&&(e.qSk(),e.j41(0,"svg",29),e.nrm(1,"path",30)(2,"path",31),e.k0s())}function u(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",32),e.bIt("click",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAddPresetColor(n,r.selectedColor))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG();e.HbH(t.cpAddColorButtonClass),e.Y8G("disabled",t.cpPresetColors&&t.cpPresetColors.length>=t.cpMaxPresetColorsLength),e.R7$(),e.SpI(" ",t.cpAddColorButtonText," ")}}function g(i,l){1&i&&e.nrm(0,"div",33)}function x(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.cmykText?null:t.cmykText.a)}}function f(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function b(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",34)(1,"div",35)(2,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onCyanInput(n))}),e.k0s(),e.j41(3,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onMagentaInput(n))}),e.k0s(),e.j41(4,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onYellowInput(n))}),e.k0s(),e.j41(5,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onBlackInput(n))}),e.k0s(),e.DNE(6,x,1,2,"input",37),e.k0s(),e.j41(7,"div",35)(8,"div"),e.EFF(9,"C"),e.k0s(),e.j41(10,"div"),e.EFF(11,"M"),e.k0s(),e.j41(12,"div"),e.EFF(13,"Y"),e.k0s(),e.j41(14,"div"),e.EFF(15,"K"),e.k0s(),e.DNE(16,f,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",3!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.c),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.m),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.y),e.R7$(),e.Y8G("rg",100)("value",null==t.cmykText?null:t.cmykText.k),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(10),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function Z(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.hslaText?null:t.hslaText.a)}}function U(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function G(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",40)(1,"div",35)(2,"input",41),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onHueInput(n))}),e.k0s(),e.j41(3,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onSaturationInput(n))}),e.k0s(),e.j41(4,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onLightnessInput(n))}),e.k0s(),e.DNE(5,Z,1,2,"input",37),e.k0s(),e.j41(6,"div",35)(7,"div"),e.EFF(8,"H"),e.k0s(),e.j41(9,"div"),e.EFF(10,"S"),e.k0s(),e.j41(11,"div"),e.EFF(12,"L"),e.k0s(),e.DNE(13,U,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",2!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",360)("value",null==t.hslaText?null:t.hslaText.h),e.R7$(),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.s),e.R7$(),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.l),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(8),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function K(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.rgbaText?null:t.rgbaText.a)}}function N(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function R(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",42)(1,"div",35)(2,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onRedInput(n))}),e.k0s(),e.j41(3,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onGreenInput(n))}),e.k0s(),e.j41(4,"input",43),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onBlueInput(n))}),e.k0s(),e.DNE(5,K,1,2,"input",37),e.k0s(),e.j41(6,"div",35)(7,"div"),e.EFF(8,"R"),e.k0s(),e.j41(9,"div"),e.EFF(10,"G"),e.k0s(),e.j41(11,"div"),e.EFF(12,"B"),e.k0s(),e.DNE(13,N,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",1!==t.format?"none":"block"),e.R7$(2),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.r),e.R7$(),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.g),e.R7$(),e.Y8G("rg",255)("value",null==t.rgbaText?null:t.rgbaText.b),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel),e.R7$(8),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function de(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",t.hexAlpha)}}function ue(i,l){1&i&&(e.j41(0,"div"),e.EFF(1,"A"),e.k0s())}function ge(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",44)(1,"div",35)(2,"input",45),e.bIt("blur",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onHexInput(null))})("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onHexInput(n))}),e.k0s(),e.DNE(3,de,1,2,"input",37),e.k0s(),e.j41(4,"div",35)(5,"div"),e.EFF(6,"Hex"),e.k0s(),e.DNE(7,ue,2,0,"div",38),e.k0s()()}if(2&i){const t=e.XpG();e.xc7("display",0!==t.format?"none":"block"),e.AVh("hex-alpha","forced"===t.cpAlphaChannel),e.R7$(2),e.Y8G("value",t.hexText),e.R7$(),e.Y8G("ngIf","forced"===t.cpAlphaChannel),e.R7$(4),e.Y8G("ngIf","forced"===t.cpAlphaChannel)}}function me(i,l){if(1&i){const t=e.RV6();e.j41(0,"input",39),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAlphaInput(n))}),e.k0s()}if(2&i){const t=e.XpG(2);e.Y8G("rg",1)("value",null==t.hslaText?null:t.hslaText.a)}}function he(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",46)(1,"div",35)(2,"input",36),e.bIt("keyup.enter",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onAcceptColor(n))})("newValue",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onValueInput(n))}),e.k0s(),e.DNE(3,me,1,2,"input",37),e.k0s(),e.j41(4,"div",35)(5,"div"),e.EFF(6,"V"),e.k0s(),e.j41(7,"div"),e.EFF(8,"A"),e.k0s()()()}if(2&i){const t=e.XpG();e.R7$(2),e.Y8G("rg",100)("value",null==t.hslaText?null:t.hslaText.l),e.R7$(),e.Y8G("ngIf","disabled"!==t.cpAlphaChannel)}}function fe(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",47)(1,"span",48),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onFormatToggle(-1))}),e.k0s(),e.j41(2,"span",48),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.onFormatToggle(1))}),e.k0s()()}}function ve(i,l){if(1&i){const t=e.RV6();e.j41(0,"span",55),e.bIt("click",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG(3);return e.Njj(s.onRemovePresetColor(n,r))}),e.k0s()}if(2&i){const t=e.XpG(4);e.HbH(t.cpRemoveColorButtonClass)}}function Ce(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",53),e.bIt("click",function(){const n=e.eBV(t).$implicit,r=e.XpG(3);return e.Njj(r.setColorFromString(n))}),e.DNE(1,ve,1,3,"span",54),e.k0s()}if(2&i){const t=l.$implicit,o=e.XpG(3);e.xc7("background-color",t),e.R7$(),e.Y8G("ngIf",o.cpAddColorButton)}}function Fe(i,l){if(1&i&&(e.j41(0,"div"),e.DNE(1,Ce,2,3,"div",52),e.k0s()),2&i){const t=e.XpG(2);e.HbH(t.cpPresetColorsClass),e.R7$(),e.Y8G("ngForOf",t.cpPresetColors)}}function _e(i,l){if(1&i&&(e.j41(0,"div"),e.EFF(1),e.k0s()),2&i){const t=e.XpG(2);e.HbH(t.cpPresetEmptyMessageClass),e.R7$(),e.JRh(t.cpPresetEmptyMessage)}}function be(i,l){if(1&i&&(e.j41(0,"div",49),e.nrm(1,"hr"),e.j41(2,"div",50),e.EFF(3),e.k0s(),e.DNE(4,Fe,2,4,"div",51)(5,_e,2,4,"div",51),e.k0s()),2&i){const t=e.XpG();e.R7$(3),e.JRh(t.cpPresetLabel),e.R7$(),e.Y8G("ngIf",null==t.cpPresetColors?null:t.cpPresetColors.length),e.R7$(),e.Y8G("ngIf",!(null!=t.cpPresetColors&&t.cpPresetColors.length)&&t.cpAddColorButton)}}function ke(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",58),e.bIt("click",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onCancelColor(n))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG(2);e.HbH(t.cpCancelButtonClass),e.R7$(),e.JRh(t.cpCancelButtonText)}}function Ee(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",58),e.bIt("click",function(n){e.eBV(t);const r=e.XpG(2);return e.Njj(r.onAcceptColor(n))}),e.EFF(1),e.k0s()}if(2&i){const t=e.XpG(2);e.HbH(t.cpOKButtonClass),e.R7$(),e.JRh(t.cpOKButtonText)}}function ye(i,l){if(1&i&&(e.j41(0,"div",56),e.DNE(1,ke,2,4,"button",57)(2,Ee,2,4,"button",57),e.k0s()),2&i){const t=e.XpG();e.R7$(),e.Y8G("ngIf",t.cpCancelButton),e.R7$(),e.Y8G("ngIf",t.cpOKButton)}}function xe(i,l){1&i&&e.eu8(0)}function we(i,l){if(1&i&&(e.j41(0,"div",59),e.DNE(1,xe,1,0,"ng-container",60),e.k0s()),2&i){const t=e.XpG();e.R7$(),e.Y8G("ngTemplateOutlet",t.cpExtraTemplate)}}var k=function(i){return i[i.HEX=0]="HEX",i[i.RGBA=1]="RGBA",i[i.HSLA=2]="HSLA",i[i.CMYK=3]="CMYK",i}(k||{});class j{r;g;b;a;constructor(l,t,o,n){this.r=l,this.g=t,this.b=o,this.a=n}}class L{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}class B{h;s;l;a;constructor(l,t,o,n){this.h=l,this.s=t,this.l=o,this.a=n}}class O{c;m;y;k;a;constructor(l,t,o,n,r=1){this.c=l,this.m=t,this.y=o,this.k=n,this.a=r}}let Te=(()=>{class i{rg;text;newValue=new e.bkB;inputChange(t){const o=t.target.value;if(void 0===this.rg)this.newValue.emit(o);else{const n=parseFloat(o);this.newValue.emit({v:n,rg:this.rg})}}static \u0275fac=function(o){return new(o||i)};static \u0275dir=e.FsC({type:i,selectors:[["","text",""]],hostBindings:function(o,n){1&o&&e.bIt("input",function(s){return n.inputChange(s)})},inputs:{rg:"rg",text:"text"},outputs:{newValue:"newValue"}})}return i})(),Ie=(()=>{class i{elRef;listenerMove;listenerStop;rgX;rgY;slider;dragEnd=new e.bkB;dragStart=new e.bkB;newValue=new e.bkB;mouseDown(t){this.start(t)}touchStart(t){this.start(t)}constructor(t){this.elRef=t,this.listenerMove=o=>this.move(o),this.listenerStop=()=>this.stop()}move(t){t.preventDefault(),this.setCursor(t)}start(t){this.setCursor(t),t.stopPropagation(),document.addEventListener("mouseup",this.listenerStop),document.addEventListener("touchend",this.listenerStop),document.addEventListener("mousemove",this.listenerMove),document.addEventListener("touchmove",this.listenerMove),this.dragStart.emit()}stop(){document.removeEventListener("mouseup",this.listenerStop),document.removeEventListener("touchend",this.listenerStop),document.removeEventListener("mousemove",this.listenerMove),document.removeEventListener("touchmove",this.listenerMove),this.dragEnd.emit()}getX(t){const o=this.elRef.nativeElement.getBoundingClientRect();return(void 0!==t.pageX?t.pageX:t.touches[0].pageX)-o.left-window.pageXOffset}getY(t){const o=this.elRef.nativeElement.getBoundingClientRect();return(void 0!==t.pageY?t.pageY:t.touches[0].pageY)-o.top-window.pageYOffset}setCursor(t){const o=this.elRef.nativeElement.offsetWidth,n=this.elRef.nativeElement.offsetHeight,r=Math.max(0,Math.min(this.getX(t),o)),s=Math.max(0,Math.min(this.getY(t),n));void 0!==this.rgX&&void 0!==this.rgY?this.newValue.emit({s:r/o,v:1-s/n,rgX:this.rgX,rgY:this.rgY}):void 0===this.rgX&&void 0!==this.rgY?this.newValue.emit({v:s/n,rgY:this.rgY}):void 0!==this.rgX&&void 0===this.rgY&&this.newValue.emit({v:r/o,rgX:this.rgX})}static \u0275fac=function(o){return new(o||i)(e.rXU(e.aKT))};static \u0275dir=e.FsC({type:i,selectors:[["","slider",""]],hostBindings:function(o,n){1&o&&e.bIt("mousedown",function(s){return n.mouseDown(s)})("touchstart",function(s){return n.touchStart(s)})},inputs:{rgX:"rgX",rgY:"rgY",slider:"slider"},outputs:{dragEnd:"dragEnd",dragStart:"dragStart",newValue:"newValue"}})}return i})();class ne{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}class oe{h;s;v;a;constructor(l,t,o,n){this.h=l,this.s=t,this.v=o,this.a=n}}let J=(()=>{class i{active=null;setActive(t){this.active&&this.active!==t&&"inline"!==this.active.cpDialogDisplay&&this.active.closeDialog(),this.active=t}hsva2hsla(t){const o=t.h,n=t.s,r=t.v,s=t.a;if(0===r)return new B(o,0,0,s);if(0===n&&1===r)return new B(o,1,1,s);{const a=r*(2-n)/2;return new B(o,r*n/(1-Math.abs(2*a-1)),a,s)}}hsla2hsva(t){const o=Math.min(t.h,1),n=Math.min(t.s,1),r=Math.min(t.l,1),s=Math.min(t.a,1);if(0===r)return new L(o,0,0,s);{const a=r+n*(1-Math.abs(2*r-1))/2;return new L(o,2*(a-r)/a,a,s)}}hsvaToRgba(t){let o,n,r;const s=t.h,a=t.s,d=t.v,p=t.a,F=Math.floor(6*s),_=6*s-F,C=d*(1-a),E=d*(1-_*a),w=d*(1-(1-_)*a);switch(F%6){case 0:o=d,n=w,r=C;break;case 1:o=E,n=d,r=C;break;case 2:o=C,n=d,r=w;break;case 3:o=C,n=E,r=d;break;case 4:o=w,n=C,r=d;break;case 5:o=d,n=C,r=E;break;default:o=0,n=0,r=0}return new j(o,n,r,p)}cmykToRgb(t){return new j((1-t.c)*(1-t.k),(1-t.m)*(1-t.k),(1-t.y)*(1-t.k),t.a)}rgbaToCmyk(t){const o=1-Math.max(t.r,t.g,t.b);return 1===o?new O(0,0,0,1,t.a):new O((1-t.r-o)/(1-o),(1-t.g-o)/(1-o),(1-t.b-o)/(1-o),o,t.a)}rgbaToHsva(t){let o,n;const r=Math.min(t.r,1),s=Math.min(t.g,1),a=Math.min(t.b,1),d=Math.min(t.a,1),p=Math.max(r,s,a),F=Math.min(r,s,a),_=p,C=p-F;if(n=0===p?0:C/p,p===F)o=0;else{switch(p){case r:o=(s-a)/C+(s{class i{ngZone;elRef;cdRef;document;platformId;service;isIE10=!1;cmyk;hsva;width;height;cmykColor;outputColor;initialColor;fallbackColor;listenerResize;listenerMouseDown;directiveInstance;sliderH;sliderDimMax;directiveElementRef;dialogArrowSize=10;dialogArrowOffset=15;dialogInputFields=[k.HEX,k.RGBA,k.HSLA,k.CMYK];useRootViewContainer=!1;show;hidden;top;left;position;format;slider;hexText;hexAlpha;cmykText;hslaText;rgbaText;arrowTop;selectedColor;hueSliderColor;alphaSliderColor;cpWidth;cpHeight;cpColorMode;cpCmykEnabled;cpAlphaChannel;cpOutputFormat;cpDisableInput;cpDialogDisplay;cpIgnoredElements;cpSaveClickOutside;cpCloseClickOutside;cpPosition;cpUsePosition;cpPositionOffset;cpOKButton;cpOKButtonText;cpOKButtonClass;cpCancelButton;cpCancelButtonText;cpCancelButtonClass;cpEyeDropper;eyeDropperSupported;cpPresetLabel;cpPresetColors;cpPresetColorsClass;cpMaxPresetColorsLength;cpPresetEmptyMessage;cpPresetEmptyMessageClass;cpAddColorButton;cpAddColorButtonText;cpAddColorButtonClass;cpRemoveColorButtonClass;cpArrowPosition;cpTriggerElement;cpExtraTemplate;dialogElement;hueSlider;alphaSlider;handleEsc(t){this.show&&"popup"===this.cpDialogDisplay&&this.onCancelColor(t)}handleEnter(t){this.show&&"popup"===this.cpDialogDisplay&&this.onAcceptColor(t)}constructor(t,o,n,r,s,a){this.ngZone=t,this.elRef=o,this.cdRef=n,this.document=r,this.platformId=s,this.service=a,this.eyeDropperSupported=(0,h.UE)(this.platformId)&&"EyeDropper"in this.document.defaultView}ngOnInit(){this.slider=new ne(0,0,0,0),this.sliderDimMax=new oe(this.hueSlider.nativeElement.offsetWidth||140,this.cpWidth,130,this.alphaSlider.nativeElement.offsetWidth||140),this.format=this.cpCmykEnabled?k.CMYK:"rgba"===this.cpOutputFormat?k.RGBA:"hsla"===this.cpOutputFormat?k.HSLA:k.HEX,this.listenerMouseDown=n=>{this.onMouseDown(n)},this.listenerResize=()=>{this.onResize()},this.openDialog(this.initialColor,!1)}ngOnDestroy(){this.closeDialog()}ngAfterViewInit(){230===this.cpWidth&&"inline"!==this.cpDialogDisplay||(this.sliderDimMax=new oe(this.hueSlider.nativeElement.offsetWidth||140,this.cpWidth,130,this.alphaSlider.nativeElement.offsetWidth||140),this.updateColorPicker(!1),this.cdRef.detectChanges())}openDialog(t,o=!0){this.service.setActive(this),this.width||(this.cpWidth=this.directiveElementRef.nativeElement.offsetWidth),this.height||(this.height=320),this.setInitialColor(t),this.setColorFromString(t,o),this.openColorPicker()}closeDialog(){this.closeColorPicker()}setupDialog(t,o,n,r,s,a,d,p,F,_,C,E,w,te,X,T,an,cn,pn,dn,un,gn,mn,hn,fn,vn,Cn,Fn,_n,bn,kn,En,yn,xn,wn,jn,An,Tn){this.setInitialColor(n),this.setColorMode(p),this.isIE10=10===function Ae(){let i="";typeof navigator<"u"&&(i=navigator.userAgent.toLowerCase());const l=i.indexOf("msie ");return l>0&&parseInt(i.substring(l+5,i.indexOf(".",l)),10)}(),this.directiveInstance=t,this.directiveElementRef=o,this.cpDisableInput=E,this.cpCmykEnabled=F,this.cpAlphaChannel=_,this.cpOutputFormat=C,this.cpDialogDisplay=a,this.cpIgnoredElements=w,this.cpSaveClickOutside=te,this.cpCloseClickOutside=X,this.useRootViewContainer=T,this.width=this.cpWidth=parseInt(r,10),this.height=this.cpHeight=parseInt(s,10),this.cpPosition=an,this.cpPositionOffset=parseInt(cn,10),this.cpOKButton=vn,this.cpOKButtonText=Fn,this.cpOKButtonClass=Cn,this.cpCancelButton=_n,this.cpCancelButtonText=kn,this.cpCancelButtonClass=bn,this.cpEyeDropper=jn,this.fallbackColor=d||"#fff",this.setPresetConfig(dn,un),this.cpPresetColorsClass=gn,this.cpMaxPresetColorsLength=mn,this.cpPresetEmptyMessage=hn,this.cpPresetEmptyMessageClass=fn,this.cpAddColorButton=En,this.cpAddColorButtonText=xn,this.cpAddColorButtonClass=yn,this.cpRemoveColorButtonClass=wn,this.cpTriggerElement=An,this.cpExtraTemplate=Tn,pn||(this.dialogArrowOffset=0),"inline"===a&&(this.dialogArrowSize=0,this.dialogArrowOffset=0),"hex"===C&&"always"!==_&&"forced"!==_&&(this.cpAlphaChannel="disabled")}setColorMode(t){switch(t.toString().toUpperCase()){case"1":case"C":case"COLOR":default:this.cpColorMode=1;break;case"2":case"G":case"GRAYSCALE":this.cpColorMode=2;break;case"3":case"P":case"PRESETS":this.cpColorMode=3}}setInitialColor(t){this.initialColor=t}setPresetConfig(t,o){this.cpPresetLabel=t,this.cpPresetColors=o}setColorFromString(t,o=!0,n=!0){let r;"always"===this.cpAlphaChannel||"forced"===this.cpAlphaChannel?(r=this.service.stringToHsva(t,!0),!r&&!this.hsva&&(r=this.service.stringToHsva(t,!1))):r=this.service.stringToHsva(t,!1),!r&&!this.hsva&&(r=this.service.stringToHsva(this.fallbackColor,!1)),r&&(this.hsva=r,this.sliderH=this.hsva.h,"hex"===this.cpOutputFormat&&"disabled"===this.cpAlphaChannel&&(this.hsva.a=1),this.updateColorPicker(o,n))}onResize(){"fixed"===this.position?this.setDialogPosition():"inline"!==this.cpDialogDisplay&&this.closeColorPicker()}onDragEnd(t){this.directiveInstance.sliderDragEnd({slider:t,color:this.outputColor})}onDragStart(t){this.directiveInstance.sliderDragStart({slider:t,color:this.outputColor})}onMouseDown(t){this.show&&!this.isIE10&&"popup"===this.cpDialogDisplay&&t.target!==this.directiveElementRef.nativeElement&&!this.isDescendant(this.elRef.nativeElement,t.target)&&!this.isDescendant(this.directiveElementRef.nativeElement,t.target)&&0===this.cpIgnoredElements.filter(o=>o===t.target).length&&this.ngZone.run(()=>{this.cpSaveClickOutside?this.directiveInstance.colorSelected(this.outputColor):(this.hsva=null,this.setColorFromString(this.initialColor,!1),this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.initialColor),this.directiveInstance.colorCanceled()),this.cpCloseClickOutside&&this.closeColorPicker()})}onAcceptColor(t){t.stopPropagation(),this.outputColor&&this.directiveInstance.colorSelected(this.outputColor),"popup"===this.cpDialogDisplay&&this.closeColorPicker()}onCancelColor(t){this.hsva=null,t.stopPropagation(),this.directiveInstance.colorCanceled(),this.setColorFromString(this.initialColor,!0),"popup"===this.cpDialogDisplay&&(this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.initialColor,!0),this.closeColorPicker())}onEyeDropper(){this.eyeDropperSupported&&(new window.EyeDropper).open().then(o=>{this.setColorFromString(o.sRGBHex,!0)})}onFormatToggle(t){const o=this.dialogInputFields.length-(this.cpCmykEnabled?0:1),n=((this.dialogInputFields.indexOf(this.format)+t)%o+o)%o;this.format=this.dialogInputFields[n]}onColorChange(t){this.hsva.s=t.s/t.rgX,this.hsva.v=t.v/t.rgY,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"lightness",value:this.hsva.v,color:this.outputColor}),this.directiveInstance.sliderChanged({slider:"saturation",value:this.hsva.s,color:this.outputColor})}onHueChange(t){this.hsva.h=t.v/t.rgX,this.sliderH=this.hsva.h,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"hue",value:this.hsva.h,color:this.outputColor})}onValueChange(t){this.hsva.v=t.v/t.rgX,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"value",value:this.hsva.v,color:this.outputColor})}onAlphaChange(t){this.hsva.a=t.v/t.rgX,this.updateColorPicker(),this.directiveInstance.sliderChanged({slider:"alpha",value:this.hsva.a,color:this.outputColor})}onHexInput(t){if(null===t)this.updateColorPicker();else{t&&"#"!==t[0]&&(t="#"+t);let o=/^#([a-f0-9]{3}|[a-f0-9]{6})$/gi;"always"===this.cpAlphaChannel&&(o=/^#([a-f0-9]{3}|[a-f0-9]{6}|[a-f0-9]{8})$/gi);const n=o.test(t);n&&(t.length<5&&(t="#"+t.substring(1).split("").map(r=>r+r).join("")),"forced"===this.cpAlphaChannel&&(t+=Math.round(255*this.hsva.a).toString(16)),this.setColorFromString(t,!0,!1)),this.directiveInstance.inputChanged({input:"hex",valid:n,value:t,color:this.outputColor})}}onRedInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.r=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"red",valid:n,value:o.r,color:this.outputColor})}onBlueInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.b=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"blue",valid:n,value:o.b,color:this.outputColor})}onGreenInput(t){const o=this.service.hsvaToRgba(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.g=t.v/t.rg,this.hsva=this.service.rgbaToHsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"green",valid:n,value:o.g,color:this.outputColor})}onHueInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.h=t.v/t.rg,this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"hue",valid:o,value:this.hsva.h,color:this.outputColor})}onValueInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.v=t.v/t.rg,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"value",valid:o,value:this.hsva.v,color:this.outputColor})}onAlphaInput(t){const o=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;o&&(this.hsva.a=t.v/t.rg,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"alpha",valid:o,value:this.hsva.a,color:this.outputColor})}onLightnessInput(t){const o=this.service.hsva2hsla(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.l=t.v/t.rg,this.hsva=this.service.hsla2hsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"lightness",valid:n,value:o.l,color:this.outputColor})}onSaturationInput(t){const o=this.service.hsva2hsla(this.hsva),n=!isNaN(t.v)&&t.v>=0&&t.v<=t.rg;n&&(o.s=t.v/t.rg,this.hsva=this.service.hsla2hsva(o),this.sliderH=this.hsva.h,this.updateColorPicker()),this.directiveInstance.inputChanged({input:"saturation",valid:n,value:o.s,color:this.outputColor})}onCyanInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.c=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"cyan",valid:!0,value:this.cmyk.c,color:this.outputColor})}onMagentaInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.m=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"magenta",valid:!0,value:this.cmyk.m,color:this.outputColor})}onYellowInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.y=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"yellow",valid:!0,value:this.cmyk.y,color:this.outputColor})}onBlackInput(t){!isNaN(t.v)&&t.v>=0&&t.v<=t.rg&&(this.cmyk.k=t.v,this.updateColorPicker(!1,!0,!0)),this.directiveInstance.inputChanged({input:"black",valid:!0,value:this.cmyk.k,color:this.outputColor})}onAddPresetColor(t,o){t.stopPropagation(),this.cpPresetColors.filter(n=>n===o).length||(this.cpPresetColors=this.cpPresetColors.concat(o),this.directiveInstance.presetColorsChanged(this.cpPresetColors))}onRemovePresetColor(t,o){t.stopPropagation(),this.cpPresetColors=this.cpPresetColors.filter(n=>n!==o),this.directiveInstance.presetColorsChanged(this.cpPresetColors)}openColorPicker(){this.show||(this.show=!0,this.hidden=!0,setTimeout(()=>{this.hidden=!1,this.setDialogPosition(),this.cdRef.detectChanges()},0),this.directiveInstance.stateChanged(!0),this.isIE10||this.ngZone.runOutsideAngular(()=>{ie?document.addEventListener("touchstart",this.listenerMouseDown):document.addEventListener("mousedown",this.listenerMouseDown)}),window.addEventListener("resize",this.listenerResize))}closeColorPicker(){this.show&&(this.show=!1,this.directiveInstance.stateChanged(!1),this.isIE10||(ie?document.removeEventListener("touchstart",this.listenerMouseDown):document.removeEventListener("mousedown",this.listenerMouseDown)),window.removeEventListener("resize",this.listenerResize),this.cdRef.destroyed||this.cdRef.detectChanges())}updateColorPicker(t=!0,o=!0,n=!1){if(this.sliderDimMax){let r,s,a;2===this.cpColorMode&&(this.hsva.s=0);const d=this.outputColor;if(s=this.service.hsva2hsla(this.hsva),this.cpCmykEnabled?(n?(a=this.service.cmykToRgb(this.service.normalizeCMYK(this.cmyk)),this.hsva=this.service.rgbaToHsva(a)):(a=this.service.hsvaToRgba(this.hsva),this.cmyk=this.service.denormalizeCMYK(this.service.rgbaToCmyk(a))),a=this.service.denormalizeRGBA(a),this.sliderH=this.hsva.h):a=this.service.denormalizeRGBA(this.service.hsvaToRgba(this.hsva)),r=this.service.denormalizeRGBA(this.service.hsvaToRgba(new L(this.sliderH||this.hsva.h,1,1,1))),o&&(this.hslaText=new B(Math.round(360*s.h),Math.round(100*s.s),Math.round(100*s.l),Math.round(100*s.a)/100),this.rgbaText=new j(a.r,a.g,a.b,Math.round(100*a.a)/100),this.cpCmykEnabled&&(this.cmykText=new O(this.cmyk.c,this.cmyk.m,this.cmyk.y,this.cmyk.k,Math.round(100*this.cmyk.a)/100)),this.hexText=this.service.rgbaToHex(a,"always"===this.cpAlphaChannel),this.hexAlpha=this.rgbaText.a),"auto"===this.cpOutputFormat&&this.format!==k.RGBA&&this.format!==k.CMYK&&this.format!==k.HSLA&&this.hsva.a<1&&(this.format=this.hsva.a<1?k.RGBA:k.HEX),this.hueSliderColor="rgb("+r.r+","+r.g+","+r.b+")",this.alphaSliderColor="rgb("+a.r+","+a.g+","+a.b+")",this.outputColor=this.service.outputFormat(this.hsva,this.cpOutputFormat,this.cpAlphaChannel),this.selectedColor=this.service.outputFormat(this.hsva,"rgba",null),this.format!==k.CMYK)this.cmykColor="";else if("always"===this.cpAlphaChannel||"enabled"===this.cpAlphaChannel||"forced"===this.cpAlphaChannel){const p=Math.round(100*this.cmyk.a)/100;this.cmykColor=`cmyka(${this.cmyk.c},${this.cmyk.m},${this.cmyk.y},${this.cmyk.k},${p})`}else this.cmykColor=`cmyk(${this.cmyk.c},${this.cmyk.m},${this.cmyk.y},${this.cmyk.k})`;this.slider=new ne((this.sliderH||this.hsva.h)*this.sliderDimMax.h-8,this.hsva.s*this.sliderDimMax.s-8,(1-this.hsva.v)*this.sliderDimMax.v-8,this.hsva.a*this.sliderDimMax.a-8),t&&d!==this.outputColor&&(this.cpCmykEnabled&&this.directiveInstance.cmykChanged(this.cmykColor),this.directiveInstance.colorChanged(this.outputColor))}}setDialogPosition(){if("inline"===this.cpDialogDisplay)this.position="relative";else{let n,t="static",o="",r=null,s=null,a=this.directiveElementRef.nativeElement.parentNode;const d=this.dialogElement.nativeElement.offsetHeight;for(;null!==a&&"HTML"!==a.tagName;){if(n=window.getComputedStyle(a),t=n.getPropertyValue("position"),o=n.getPropertyValue("transform"),"static"!==t&&null===r&&(r=a),o&&"none"!==o&&null===s&&(s=a),"fixed"===t){r=s;break}a=a.parentNode}const p=this.createDialogBox(this.directiveElementRef.nativeElement,"fixed"!==t);if(this.useRootViewContainer||"fixed"===t&&(!r||r instanceof HTMLUnknownElement))this.top=p.top,this.left=p.left;else{null===r&&(r=a);const T=this.createDialogBox(r,"fixed"!==t);this.top=p.top-T.top,this.left=p.left-T.left}"fixed"===t&&(this.position="fixed");let F=this.cpPosition;const _=this.dialogElement.nativeElement.getBoundingClientRect();switch("auto"===this.cpPosition&&(F=function je(i,l){let t="right",o="bottom";const{height:n,width:r}=i,{top:s,left:a}=l,d=s+l.height,p=a+l.width,F=s-n<0,_=d+n>(window.innerHeight||document.documentElement.clientHeight),C=a-r<0,E=p+r>(window.innerWidth||document.documentElement.clientWidth);return _&&(o="top"),F&&(o="bottom"),C&&(t="right"),E&&(t="left"),F&&_&&C&&E?["left","right","top","bottom"].reduce((X,T)=>i[X]>i[T]?X:T):C&&E?F?"bottom":_||s>d?"top":"bottom":F&&_?C?"right":E||a>p?"left":"right":`${o}-${t}`}(_,this.cpTriggerElement.nativeElement.getBoundingClientRect())),this.arrowTop="top"===F?d-1:void 0,this.cpArrowPosition=void 0,F){case"top":this.top-=d+this.dialogArrowSize,this.left+=this.cpPositionOffset/100*p.width-this.dialogArrowOffset;break;case"bottom":this.top+=p.height+this.dialogArrowSize,this.left+=this.cpPositionOffset/100*p.width-this.dialogArrowOffset;break;case"top-left":case"left-top":this.top-=d-p.height+p.height*this.cpPositionOffset/100,this.left-=this.cpWidth+this.dialogArrowSize-2-this.dialogArrowOffset;break;case"top-right":case"right-top":this.top-=d-p.height+p.height*this.cpPositionOffset/100,this.left+=p.width+this.dialogArrowSize-2-this.dialogArrowOffset;break;case"left":case"bottom-left":case"left-bottom":this.top+=p.height*this.cpPositionOffset/100-this.dialogArrowOffset,this.left-=this.cpWidth+this.dialogArrowSize-2;break;default:this.top+=p.height*this.cpPositionOffset/100-this.dialogArrowOffset,this.left+=p.width+this.dialogArrowSize-2}const C=window.innerHeight,E=window.innerWidth,w=this.elRef.nativeElement.getBoundingClientRect();this.top+_.height>C&&(this.top=C-_.height,this.cpArrowPosition=w.x/2-20),this.left+_.width>E&&(this.left=E-_.width,this.cpArrowPosition=w.x/2-20),this.cpUsePosition=F}}isDescendant(t,o){let n=o.parentNode;for(;null!==n;){if(n===t)return!0;n=n.parentNode}return!1}createDialogBox(t,o){const{top:n,left:r}=t.getBoundingClientRect();return{top:n+(o?window.pageYOffset:0),left:r+(o?window.pageXOffset:0),width:t.offsetWidth,height:t.offsetHeight}}static \u0275fac=function(o){return new(o||i)(e.rXU(e.SKi),e.rXU(e.aKT),e.rXU(e.gRc),e.rXU(h.qQ),e.rXU(e.Agw),e.rXU(J))};static \u0275cmp=e.VBU({type:i,selectors:[["color-picker"]],viewQuery:function(o,n){if(1&o&&(e.GBs(S,7),e.GBs(H,7),e.GBs(D,7)),2&o){let r;e.mGM(r=e.lsd())&&(n.dialogElement=r.first),e.mGM(r=e.lsd())&&(n.hueSlider=r.first),e.mGM(r=e.lsd())&&(n.alphaSlider=r.first)}},hostBindings:function(o,n){1&o&&e.bIt("keyup.esc",function(s){return n.handleEsc(s)},!1,e.EBC)("keyup.enter",function(s){return n.handleEnter(s)},!1,e.EBC)},decls:30,vars:51,consts:[["dialogPopup",""],["hueSlider",""],["valueSlider",""],["alphaSlider",""],[1,"color-picker",3,"click"],[3,"left","class","top",4,"ngIf"],["class","saturation-lightness",3,"slider","rgX","rgY","background-color","newValue","dragStart","dragEnd",4,"ngIf"],[1,"hue-alpha","box"],[1,"left"],[1,"selected-color-background"],[1,"selected-color",3,"click"],["class","eyedropper-icon","xmlns","http://www.w3.org/2000/svg","height","24px","viewBox","0 0 24 24","width","24px","fill","#000000",4,"ngIf"],["type","button",3,"class","disabled","click",4,"ngIf"],[1,"right"],["style","height: 16px;",4,"ngIf"],[1,"hue",3,"newValue","dragStart","dragEnd","slider","rgX"],[1,"cursor"],[1,"value",3,"newValue","dragStart","dragEnd","slider","rgX"],[1,"alpha",3,"newValue","dragStart","dragEnd","slider","rgX"],["class","cmyk-text",3,"display",4,"ngIf"],["class","hsla-text",3,"display",4,"ngIf"],["class","rgba-text",3,"display",4,"ngIf"],["class","hex-text",3,"hex-alpha","display",4,"ngIf"],["class","value-text",4,"ngIf"],["class","type-policy",4,"ngIf"],["class","preset-area",4,"ngIf"],["class","button-area",4,"ngIf"],["class","extra-template",4,"ngIf"],[1,"saturation-lightness",3,"newValue","dragStart","dragEnd","slider","rgX","rgY"],["xmlns","http://www.w3.org/2000/svg","height","24px","viewBox","0 0 24 24","width","24px","fill","#000000",1,"eyedropper-icon"],["d","M0 0h24v24H0V0z","fill","none"],["d","M17.66 5.41l.92.92-2.69 2.69-.92-.92 2.69-2.69M17.67 3c-.26 0-.51.1-.71.29l-3.12 3.12-1.93-1.91-1.41 1.41 1.42 1.42L3 16.25V21h4.75l8.92-8.92 1.42 1.42 1.41-1.41-1.92-1.92 3.12-3.12c.4-.4.4-1.03.01-1.42l-2.34-2.34c-.2-.19-.45-.29-.7-.29zM6.92 19L5 17.08l8.06-8.06 1.92 1.92L6.92 19z"],["type","button",3,"click","disabled"],[2,"height","16px"],[1,"cmyk-text"],[1,"box"],["type","number","pattern","[0-9]*","min","0","max","100",3,"keyup.enter","newValue","text","rg","value"],["type","number","pattern","[0-9]+([\\.,][0-9]{1,2})?","min","0","max","1","step","0.1",3,"text","rg","value","keyup.enter","newValue",4,"ngIf"],[4,"ngIf"],["type","number","pattern","[0-9]+([\\.,][0-9]{1,2})?","min","0","max","1","step","0.1",3,"keyup.enter","newValue","text","rg","value"],[1,"hsla-text"],["type","number","pattern","[0-9]*","min","0","max","360",3,"keyup.enter","newValue","text","rg","value"],[1,"rgba-text"],["type","number","pattern","[0-9]*","min","0","max","255",3,"keyup.enter","newValue","text","rg","value"],[1,"hex-text"],[3,"blur","keyup.enter","newValue","text","value"],[1,"value-text"],[1,"type-policy"],[1,"type-policy-arrow",3,"click"],[1,"preset-area"],[1,"preset-label"],[3,"class",4,"ngIf"],["class","preset-color",3,"backgroundColor","click",4,"ngFor","ngForOf"],[1,"preset-color",3,"click"],[3,"class","click",4,"ngIf"],[3,"click"],[1,"button-area"],["type","button",3,"class","click",4,"ngIf"],["type","button",3,"click"],[1,"extra-template"],[4,"ngTemplateOutlet"]],template:function(o,n){if(1&o){const r=e.RV6();e.j41(0,"div",4,0),e.bIt("click",function(a){return e.eBV(r),e.Njj(a.stopPropagation())}),e.DNE(2,y,1,7,"div",5)(3,z,2,8,"div",6),e.j41(4,"div",7)(5,"div",8),e.nrm(6,"div",9),e.j41(7,"div",10),e.bIt("click",function(){return e.eBV(r),e.Njj(n.eyeDropperSupported&&n.cpEyeDropper&&n.onEyeDropper())}),e.DNE(8,M,3,0,"svg",11),e.k0s(),e.DNE(9,u,2,5,"button",12),e.k0s(),e.j41(10,"div",13),e.DNE(11,g,1,0,"div",14),e.j41(12,"div",15,1),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onHueChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("hue"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("hue"))}),e.nrm(14,"div",16),e.k0s(),e.j41(15,"div",17,2),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onValueChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("value"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("value"))}),e.nrm(17,"div",16),e.k0s(),e.j41(18,"div",18,3),e.bIt("newValue",function(a){return e.eBV(r),e.Njj(n.onAlphaChange(a))})("dragStart",function(){return e.eBV(r),e.Njj(n.onDragStart("alpha"))})("dragEnd",function(){return e.eBV(r),e.Njj(n.onDragEnd("alpha"))}),e.nrm(20,"div",16),e.k0s()()(),e.DNE(21,b,17,12,"div",19)(22,G,14,10,"div",20)(23,R,14,10,"div",21)(24,ge,8,7,"div",22)(25,he,9,3,"div",23)(26,fe,3,0,"div",24)(27,be,6,3,"div",25)(28,ye,3,2,"div",26)(29,we,2,1,"div",27),e.k0s()}2&o&&(e.xc7("display",n.show?"block":"none")("visibility",n.hidden?"hidden":"visible")("top",n.top,"px")("left",n.left,"px")("position",n.position)("height",n.cpHeight,"px")("width",n.cpWidth,"px"),e.AVh("open",n.show),e.R7$(2),e.Y8G("ngIf","popup"===n.cpDialogDisplay),e.R7$(),e.Y8G("ngIf",1===(n.cpColorMode||1)),e.R7$(4),e.xc7("background-color",n.selectedColor)("cursor",n.eyeDropperSupported&&n.cpEyeDropper?"pointer":null),e.R7$(),e.Y8G("ngIf",n.eyeDropperSupported&&n.cpEyeDropper),e.R7$(),e.Y8G("ngIf",n.cpAddColorButton),e.R7$(2),e.Y8G("ngIf","disabled"===n.cpAlphaChannel),e.R7$(),e.xc7("display",1===(n.cpColorMode||1)?"block":"none"),e.Y8G("rgX",1),e.R7$(2),e.xc7("left",null==n.slider?null:n.slider.h,"px"),e.R7$(),e.xc7("display",2===(n.cpColorMode||1)?"block":"none"),e.Y8G("rgX",1),e.R7$(2),e.xc7("right",null==n.slider?null:n.slider.v,"px"),e.R7$(),e.xc7("display","disabled"===n.cpAlphaChannel?"none":"block")("background-color",n.alphaSliderColor),e.Y8G("rgX",1),e.R7$(2),e.xc7("left",null==n.slider?null:n.slider.a,"px"),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&2===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",!n.cpDisableInput&&1===(n.cpColorMode||1)),e.R7$(),e.Y8G("ngIf",(null==n.cpPresetColors?null:n.cpPresetColors.length)||n.cpAddColorButton),e.R7$(),e.Y8G("ngIf",n.cpOKButton||n.cpCancelButton),e.R7$(),e.Y8G("ngIf",n.cpExtraTemplate))},dependencies:[h.Sq,h.bT,h.T3,Te,Ie],styles:['.color-picker{position:absolute;z-index:1000;width:230px;height:auto;border:#777 solid 1px;cursor:default;-webkit-user-select:none;user-select:none;background-color:#fff}.color-picker *{box-sizing:border-box;margin:0;font-size:11px}.color-picker input{width:0;height:26px;min-width:0;font-size:13px;text-align:center;color:#000}.color-picker input:invalid,.color-picker input:-moz-ui-invalid,.color-picker input:-moz-submit-invalid{box-shadow:none}.color-picker input::-webkit-inner-spin-button,.color-picker input::-webkit-outer-spin-button{margin:0;-webkit-appearance:none}.color-picker .arrow{position:absolute;z-index:999999;width:0;height:0;border-style:solid}.color-picker .arrow.arrow-top{left:8px;border-width:10px 5px;border-color:#777 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .arrow.arrow-bottom{top:-20px;left:8px;border-width:10px 5px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) #777 rgba(0,0,0,0)}.color-picker .arrow.arrow-top-left,.color-picker .arrow.arrow-left-top{right:-21px;bottom:8px;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.color-picker .arrow.arrow-top-right,.color-picker .arrow.arrow-right-top{bottom:8px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .arrow.arrow-left,.color-picker .arrow.arrow-left-bottom,.color-picker .arrow.arrow-bottom-left{top:8px;right:-21px;border-width:5px 10px;border-color:rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0) #777}.color-picker .arrow.arrow-right,.color-picker .arrow.arrow-right-bottom,.color-picker .arrow.arrow-bottom-right{top:8px;left:-20px;border-width:5px 10px;border-color:rgba(0,0,0,0) #777 rgba(0,0,0,0) rgba(0,0,0,0)}.color-picker .cursor{position:relative;width:16px;height:16px;border:#222 solid 2px;border-radius:50%;cursor:default}.color-picker .box{display:flex;padding:4px 8px}.color-picker .left{position:relative;padding:16px 8px}.color-picker .right{flex:1 1 auto;padding:12px 8px}.color-picker .button-area{padding:0 16px 16px;text-align:right}.color-picker .button-area button{margin-left:8px}.color-picker .preset-area{padding:4px 15px}.color-picker .preset-area .preset-label{overflow:hidden;width:100%;padding:4px;font-size:11px;white-space:nowrap;text-align:left;text-overflow:ellipsis;color:#555}.color-picker .preset-area .preset-color{position:relative;display:inline-block;width:18px;height:18px;margin:4px 6px 8px;border:#a9a9a9 solid 1px;border-radius:25%;cursor:pointer}.color-picker .preset-area .preset-empty-message{min-height:18px;margin-top:4px;margin-bottom:8px;font-style:italic;text-align:center}.color-picker .hex-text{width:100%;padding:4px 8px;font-size:11px}.color-picker .hex-text .box{padding:0 24px 8px 8px}.color-picker .hex-text .box div{float:left;flex:1 1 auto;text-align:center;color:#555;clear:left}.color-picker .hex-text .box input{flex:1 1 auto;padding:1px;border:#a9a9a9 solid 1px}.color-picker .hex-alpha .box div:first-child,.color-picker .hex-alpha .box input:first-child{flex-grow:3;margin-right:8px}.color-picker .cmyk-text,.color-picker .hsla-text,.color-picker .rgba-text,.color-picker .value-text{width:100%;padding:4px 8px;font-size:11px}.color-picker .cmyk-text .box,.color-picker .hsla-text .box,.color-picker .rgba-text .box{padding:0 24px 8px 8px}.color-picker .value-text .box{padding:0 8px 8px}.color-picker .cmyk-text .box div,.color-picker .hsla-text .box div,.color-picker .rgba-text .box div,.color-picker .value-text .box div{flex:1 1 auto;margin-right:8px;text-align:center;color:#555}.color-picker .cmyk-text .box div:last-child,.color-picker .hsla-text .box div:last-child,.color-picker .rgba-text .box div:last-child,.color-picker .value-text .box div:last-child{margin-right:0}.color-picker .cmyk-text .box input,.color-picker .hsla-text .box input,.color-picker .rgba-text .box input,.color-picker .value-text .box input{float:left;flex:1;padding:1px;margin:0 8px 0 0;border:#a9a9a9 solid 1px}.color-picker .cmyk-text .box input:last-child,.color-picker .hsla-text .box input:last-child,.color-picker .rgba-text .box input:last-child,.color-picker .value-text .box input:last-child{margin-right:0}.color-picker .hue-alpha{align-items:center;margin-bottom:3px}.color-picker .hue{direction:ltr;width:100%;height:16px;margin-bottom:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwkUFWbCCAAAAFxJREFUaN7t0kEKg0AQAME2x83/n2qu5qCgD1iDhCoYdpnbQC9bbY1qVO/jvc6k3ad91s7/7F1/csgPrujuQ17BDYSFsBAWwgJhISyEBcJCWAgLhIWwEBYIi2f7Ar/1TCgFH2X9AAAAAElFTkSuQmCC)}.color-picker .value{direction:rtl;width:100%;height:16px;margin-bottom:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAACTklEQVR42u3SYUcrABhA4U2SkmRJMmWSJklKJiWZZpKUJJskKUmaTFImKZOUzMySpGRmliRNJilJSpKSJEtmSpIpmWmSdO736/6D+x7OP3gUCoWCv1cqlSQlJZGcnExKSgqpqamkpaWRnp5ORkYGmZmZqFQqsrKyyM7OJicnh9zcXNRqNXl5eeTn56PRaCgoKKCwsJCioiK0Wi3FxcWUlJRQWlpKWVkZ5eXlVFRUUFlZiU6no6qqiurqampqaqitraWurg69Xk99fT0GgwGj0UhDQwONjY00NTXR3NxMS0sLra2ttLW10d7ejslkwmw209HRQWdnJ11dXXR3d9PT00Nvby99fX309/czMDDA4OAgFouFoaEhrFYrw8PDjIyMMDo6ytjYGDabjfHxcSYmJpicnGRqagq73c709DQzMzPMzs4yNzfH/Pw8DocDp9OJy+XC7XazsLDA4uIiS0tLLC8vs7KywurqKmtra3g8HrxeLz6fD7/fz/r6OhsbG2xubrK1tcX29jaBQICdnR2CwSC7u7vs7e2xv7/PwcEBh4eHHB0dcXx8zMnJCaenp5ydnXF+fs7FxQWXl5dcXV1xfX3Nzc0Nt7e33N3dEQqFuL+/5+HhgXA4TCQS4fHxkaenJ56fn3l5eeH19ZVoNMrb2xvv7+98fHwQi8WIx+N8fn6SSCT4+vri+/ubn58ffn9/+VcKgSWwBJbAElgCS2AJLIElsASWwBJYAktgCSyBJbAElsASWAJLYAksgSWwBJbAElgCS2AJLIElsP4/WH8AmJ5Z6jHS4h8AAAAASUVORK5CYII=)}.color-picker .alpha{direction:ltr;width:100%;height:16px;border:none;cursor:pointer;background-size:100% 100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwYQlZMa3gAAAWVJREFUaN7tmEGO6jAQRCsOArHgBpyAJYGjcGocxAm4A2IHpmoWE0eBH+ezmFlNvU06shJ3W6VEelWMUQAIIF9f6qZpimsA1LYtS2uF51/u27YVAFZVRUkEoGHdPV/sIcbIEIIkUdI/9Xa7neyv61+SWFUVAVCSct00TWn2fv6u3+Ecfd3tXzy/0+nEUu+SPjo/kqzrmiQpScN6v98XewfA8/lMkiLJ2WxGSUopcT6fM6U0NX9/frfbjev1WtfrlZfLhYfDQQHG/AIOlnGwjINlHCxjHCzjYJm/TJWdCwquJXseFFzGwDNNeiKMOJTO8xQdDQaeB29+K9efeLaBo9J7vdvtJj1RjFFjfiv7qv95tjx/7leSQgh93e1ffMeIp6O+YQjho/N791t1XVOSSI7N//K+4/GoxWLBx+PB5/Op5XLJ+/3OlJJWqxU3m83ovv5iGf8KjYNlHCxjHCzjYBkHy5gf5gusvQU7U37jTAAAAABJRU5ErkJggg==)}.color-picker .type-policy{position:absolute;top:218px;right:12px;width:16px;height:24px;background-size:8px 16px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAYAAAAffCjxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAACewAAAnsB01CO3AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIASURBVEiJ7ZY9axRRFIafsxMStrLQJpAgpBFhi+C9w1YSo00I6RZ/g9vZpBf/QOr4GyRgkSKNSrAadsZqQGwCkuAWyRZJsySwvhZ7N/vhzrgbLH3Ld8597jlzz50zJokyxXH8DqDVar0qi6v8BbItqSGpEcfxdlmsFWXkvX8AfAVWg3UKPEnT9GKujMzsAFgZsVaCN1VTQd77XUnrgE1kv+6935268WRpzrnHZvYRWC7YvC3pRZZl3wozqtVqiyH9IgjAspkd1Gq1xUJQtVrdB9ZKIAOthdg/Qc65LUk7wNIMoCVJO865rYFhkqjX6/d7vV4GPJwBMqofURS5JEk6FYBer/eeYb/Mo9WwFnPOvQbeAvfuAAK4BN4sAJtAG/gJIElmNuiJyba3EGNmZiPeZuEVmVell/Y/6N+CzDn3AXhEOOo7Hv/3BeAz8IzQkMPnJbuPx1wC+yYJ7/0nYIP5S/0FHKdp+rwCEEXRS/rf5Hl1Gtb2M0iSpCOpCZzPATmX1EySpHMLAsiy7MjMDoHrGSDXZnaYZdnRwBh7J91utwmczAA6CbG3GgPleX4jqUH/a1CktqRGnuc3hSCAMB32gKspkCtgb3KCQMmkjeP4WNJThrNNZval1WptTIsv7JtQ4tmIdRa8qSoEpWl6YWZNoAN0zKxZNPehpLSBZv2t+Q0CJ9lLnARQLAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-position:center}.color-picker .type-policy .type-policy-arrow{display:block;width:100%;height:50%}.color-picker .selected-color{position:absolute;top:16px;left:8px;width:40px;height:40px;border:1px solid #a9a9a9;border-radius:50%}.color-picker .selected-color-background{width:40px;height:40px;border-radius:50%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAh0lEQVRYR+2W0QlAMQgD60zdfwOdqa8TmI/wQMr5K0I5bZLIzLOa2nt37VVVbd+dDx5obgCC3KBLwJ2ff4PnVidkf+ucIhw80HQaCLo3DMH3CRK3iFsmAWVl6hPNDwt8EvNE5q+YuEXcMgkonVM6SdyCoEvAnZ8v1Hjx817MilmxSUB5rdLJDycZgUAZUch/AAAAAElFTkSuQmCC)}.color-picker .saturation-lightness{direction:ltr;width:100%;height:130px;border:none;cursor:pointer;touch-action:manipulation;background-size:100% 100%;background-image:url(data:image/png;base64,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)}.color-picker .cp-add-color-button-class{position:absolute;display:inline;padding:0;margin:3px -3px;border:0;cursor:pointer;background:transparent}.color-picker .cp-add-color-button-class:hover{text-decoration:underline}.color-picker .cp-add-color-button-class:disabled{cursor:not-allowed;color:#999}.color-picker .cp-add-color-button-class:disabled:hover{text-decoration:none}.color-picker .cp-remove-color-button-class{position:absolute;top:-5px;right:-5px;display:block;width:10px;height:10px;border-radius:50%;cursor:pointer;text-align:center;background:#fff;box-shadow:1px 1px 5px #333}.color-picker .cp-remove-color-button-class:before{content:"x";position:relative;bottom:3.5px;display:inline-block;font-size:10px}.color-picker .eyedropper-icon{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);fill:#fff;mix-blend-mode:exclusion}\n'],encapsulation:2})}return i})(),Be=(()=>{class i{injector;cfr;appRef;vcRef;elRef;_service;dialog;dialogCreated=!1;ignoreChanges=!1;cmpRef;viewAttachedToAppRef=!1;colorPicker;cpWidth="230px";cpHeight="auto";cpToggle=!1;cpDisabled=!1;cpIgnoredElements=[];cpFallbackColor="";cpColorMode="color";cpCmykEnabled=!1;cpOutputFormat="auto";cpAlphaChannel="enabled";cpDisableInput=!1;cpDialogDisplay="popup";cpSaveClickOutside=!0;cpCloseClickOutside=!0;cpUseRootViewContainer=!1;cpPosition="auto";cpPositionOffset="0%";cpPositionRelativeToArrow=!1;cpOKButton=!1;cpOKButtonText="OK";cpOKButtonClass="cp-ok-button-class";cpCancelButton=!1;cpCancelButtonText="Cancel";cpCancelButtonClass="cp-cancel-button-class";cpEyeDropper=!1;cpPresetLabel="Preset colors";cpPresetColors;cpPresetColorsClass="cp-preset-colors-class";cpMaxPresetColorsLength=6;cpPresetEmptyMessage="No colors added";cpPresetEmptyMessageClass="preset-empty-message";cpAddColorButton=!1;cpAddColorButtonText="Add color";cpAddColorButtonClass="cp-add-color-button-class";cpRemoveColorButtonClass="cp-remove-color-button-class";cpArrowPosition=0;cpExtraTemplate;cpInputChange=new e.bkB(!0);cpToggleChange=new e.bkB(!0);cpSliderChange=new e.bkB(!0);cpSliderDragEnd=new e.bkB(!0);cpSliderDragStart=new e.bkB(!0);colorPickerOpen=new e.bkB(!0);colorPickerClose=new e.bkB(!0);colorPickerCancel=new e.bkB(!0);colorPickerSelect=new e.bkB(!0);colorPickerChange=new e.bkB(!1);cpCmykColorChange=new e.bkB(!0);cpPresetColorsChange=new e.bkB(!0);handleClick(){this.inputFocus()}handleFocus(){this.inputFocus()}handleInput(t){this.inputChange(t)}constructor(t,o,n,r,s,a){this.injector=t,this.cfr=o,this.appRef=n,this.vcRef=r,this.elRef=s,this._service=a}ngOnDestroy(){null!=this.cmpRef&&(this.viewAttachedToAppRef&&this.appRef.detachView(this.cmpRef.hostView),this.cmpRef.destroy(),this.cmpRef=null,this.dialog=null)}ngOnChanges(t){t.cpToggle&&!this.cpDisabled&&(t.cpToggle.currentValue?this.openDialog():t.cpToggle.currentValue||this.closeDialog()),t.colorPicker&&(this.dialog&&!this.ignoreChanges&&("inline"===this.cpDialogDisplay&&this.dialog.setInitialColor(t.colorPicker.currentValue),this.dialog.setColorFromString(t.colorPicker.currentValue,!1),this.cpUseRootViewContainer&&"inline"!==this.cpDialogDisplay&&this.cmpRef.changeDetectorRef.detectChanges()),this.ignoreChanges=!1),(t.cpPresetLabel||t.cpPresetColors)&&this.dialog&&this.dialog.setPresetConfig(this.cpPresetLabel,this.cpPresetColors)}openDialog(){if(this.dialogCreated)this.dialog&&this.dialog.openDialog(this.colorPicker);else{let t=this.vcRef;if(this.dialogCreated=!0,this.viewAttachedToAppRef=!1,this.cpUseRootViewContainer&&"inline"!==this.cpDialogDisplay){const r=this.injector.get(this.appRef.componentTypes[0],e.zZn.NULL);r!==e.zZn.NULL?t=r.vcRef||r.viewContainerRef||this.vcRef:this.viewAttachedToAppRef=!0}const o=this.cfr.resolveComponentFactory(Se);if(this.viewAttachedToAppRef)this.cmpRef=o.create(this.injector),this.appRef.attachView(this.cmpRef.hostView),document.body.appendChild(this.cmpRef.hostView.rootNodes[0]);else{const n=e.zZn.create({providers:[],parent:t.injector});this.cmpRef=t.createComponent(o,0,n,[])}this.cmpRef.instance.setupDialog(this,this.elRef,this.colorPicker,this.cpWidth,this.cpHeight,this.cpDialogDisplay,this.cpFallbackColor,this.cpColorMode,this.cpCmykEnabled,this.cpAlphaChannel,this.cpOutputFormat,this.cpDisableInput,this.cpIgnoredElements,this.cpSaveClickOutside,this.cpCloseClickOutside,this.cpUseRootViewContainer,this.cpPosition,this.cpPositionOffset,this.cpPositionRelativeToArrow,this.cpPresetLabel,this.cpPresetColors,this.cpPresetColorsClass,this.cpMaxPresetColorsLength,this.cpPresetEmptyMessage,this.cpPresetEmptyMessageClass,this.cpOKButton,this.cpOKButtonClass,this.cpOKButtonText,this.cpCancelButton,this.cpCancelButtonClass,this.cpCancelButtonText,this.cpAddColorButton,this.cpAddColorButtonClass,this.cpAddColorButtonText,this.cpRemoveColorButtonClass,this.cpEyeDropper,this.elRef,this.cpExtraTemplate),this.dialog=this.cmpRef.instance,this.vcRef!==t&&this.cmpRef.changeDetectorRef.detectChanges()}}closeDialog(){this.dialog&&"popup"===this.cpDialogDisplay&&this.dialog.closeDialog()}cmykChanged(t){this.cpCmykColorChange.emit(t)}stateChanged(t){this.cpToggleChange.emit(t),t?this.colorPickerOpen.emit(this.colorPicker):this.colorPickerClose.emit(this.colorPicker)}colorChanged(t,o=!0){this.ignoreChanges=o,this.colorPickerChange.emit(t)}colorSelected(t){this.colorPickerSelect.emit(t)}colorCanceled(){this.colorPickerCancel.emit()}inputFocus(){const t=this.elRef.nativeElement,o=this.cpIgnoredElements.filter(n=>n===t);!this.cpDisabled&&!o.length&&(typeof document<"u"&&t===document.activeElement?this.openDialog():this.dialog&&this.dialog.show?this.closeDialog():this.openDialog())}inputChange(t){this.dialog?this.dialog.setColorFromString(t.target.value,!0):(this.colorPicker=t.target.value,this.colorPickerChange.emit(this.colorPicker))}inputChanged(t){this.cpInputChange.emit(t)}sliderChanged(t){this.cpSliderChange.emit(t)}sliderDragEnd(t){this.cpSliderDragEnd.emit(t)}sliderDragStart(t){this.cpSliderDragStart.emit(t)}presetColorsChanged(t){this.cpPresetColorsChange.emit(t)}static \u0275fac=function(o){return new(o||i)(e.rXU(e.zZn),e.rXU(e.OM3),e.rXU(e.o8S),e.rXU(e.c1b),e.rXU(e.aKT),e.rXU(J))};static \u0275dir=e.FsC({type:i,selectors:[["","colorPicker",""]],hostBindings:function(o,n){1&o&&e.bIt("click",function(){return n.handleClick()})("focus",function(){return n.handleFocus()})("input",function(s){return n.handleInput(s)})},inputs:{colorPicker:"colorPicker",cpWidth:"cpWidth",cpHeight:"cpHeight",cpToggle:"cpToggle",cpDisabled:"cpDisabled",cpIgnoredElements:"cpIgnoredElements",cpFallbackColor:"cpFallbackColor",cpColorMode:"cpColorMode",cpCmykEnabled:"cpCmykEnabled",cpOutputFormat:"cpOutputFormat",cpAlphaChannel:"cpAlphaChannel",cpDisableInput:"cpDisableInput",cpDialogDisplay:"cpDialogDisplay",cpSaveClickOutside:"cpSaveClickOutside",cpCloseClickOutside:"cpCloseClickOutside",cpUseRootViewContainer:"cpUseRootViewContainer",cpPosition:"cpPosition",cpPositionOffset:"cpPositionOffset",cpPositionRelativeToArrow:"cpPositionRelativeToArrow",cpOKButton:"cpOKButton",cpOKButtonText:"cpOKButtonText",cpOKButtonClass:"cpOKButtonClass",cpCancelButton:"cpCancelButton",cpCancelButtonText:"cpCancelButtonText",cpCancelButtonClass:"cpCancelButtonClass",cpEyeDropper:"cpEyeDropper",cpPresetLabel:"cpPresetLabel",cpPresetColors:"cpPresetColors",cpPresetColorsClass:"cpPresetColorsClass",cpMaxPresetColorsLength:"cpMaxPresetColorsLength",cpPresetEmptyMessage:"cpPresetEmptyMessage",cpPresetEmptyMessageClass:"cpPresetEmptyMessageClass",cpAddColorButton:"cpAddColorButton",cpAddColorButtonText:"cpAddColorButtonText",cpAddColorButtonClass:"cpAddColorButtonClass",cpRemoveColorButtonClass:"cpRemoveColorButtonClass",cpArrowPosition:"cpArrowPosition",cpExtraTemplate:"cpExtraTemplate"},outputs:{cpInputChange:"cpInputChange",cpToggleChange:"cpToggleChange",cpSliderChange:"cpSliderChange",cpSliderDragEnd:"cpSliderDragEnd",cpSliderDragStart:"cpSliderDragStart",colorPickerOpen:"colorPickerOpen",colorPickerClose:"colorPickerClose",colorPickerCancel:"colorPickerCancel",colorPickerSelect:"colorPickerSelect",colorPickerChange:"colorPickerChange",cpCmykColorChange:"cpCmykColorChange",cpPresetColorsChange:"cpPresetColorsChange"},exportAs:["ngxColorPicker"],features:[e.OA$]})}return i})(),Ve=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({providers:[J],imports:[h.MD]})}return i})();var Pe=m(2578);let Q;try{Q=!!new Blob}catch{Q=!1}let re=(()=>{class i{get isFileSaverSupported(){return Q}genType(t){if(!t||-1===t.lastIndexOf("."))return"text/plain";const o=t.substring(t.lastIndexOf(".")+1);switch(o){case"txt":return"text/plain";case"xml":case"html":return`text/${o}`;case"json":return"octet/stream";default:return`application/${o}`}}save(t,o,n,r){if(!t)throw new Error("Data argument should be a blob instance");const s=new Blob([t],{type:n||t.type||this.genType(o)});(0,Pe.saveAs)(s,decodeURI(o||"download"),r)}saveText(t,o,n){const r=new Blob([t]);this.save(r,o,void 0,n)}static#e=this.\u0275fac=function(o){return new(o||i)};static#t=this.\u0275prov=e.jDH({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),De=(()=>{class i{static#e=this.\u0275fac=function(o){return new(o||i)};static#t=this.\u0275mod=e.$C({type:i});static#n=this.\u0275inj=e.G2t({})}return i})();const Me=i=>["segment",i],Ge=(i,l)=>({"segment-main":!0,expandable:i,expanded:l});function Ne(i,l){1&i&&e.nrm(0,"div",9)}function Oe(i,l){if(1&i&&(e.j41(0,"span",10),e.EFF(1),e.k0s()),2&i){const t=e.XpG().$implicit;e.R7$(),e.JRh(t.description)}}function Xe(i,l){if(1&i&&(e.j41(0,"section",11),e.nrm(1,"ngx-json-viewer",12),e.k0s()),2&i){const t=e.XpG().$implicit,o=e.XpG();e.R7$(),e.Y8G("json",t.value)("expanded",o.expanded)("depth",o.depth)("_currentDepth",o._currentDepth+1)}}function Ye(i,l){if(1&i){const t=e.RV6();e.j41(0,"section",2)(1,"section",3),e.bIt("click",function(){const n=e.eBV(t).$implicit,r=e.XpG();return e.Njj(r.toggle(n))}),e.DNE(2,Ne,1,0,"div",4),e.j41(3,"span",5),e.EFF(4),e.k0s(),e.j41(5,"span",6),e.EFF(6,": "),e.k0s(),e.DNE(7,Oe,2,1,"span",7),e.k0s(),e.DNE(8,Xe,2,4,"section",8),e.k0s()}if(2&i){const t=l.$implicit,o=e.XpG();e.Y8G("ngClass",e.eq3(6,Me,"segment-type-"+t.type)),e.R7$(),e.Y8G("ngClass",e.l_i(8,Ge,o.isExpandable(t),t.expanded)),e.R7$(),e.Y8G("ngIf",o.isExpandable(t)),e.R7$(2),e.JRh(t.key),e.R7$(3),e.Y8G("ngIf",!t.expanded||!o.isExpandable(t)),e.R7$(),e.Y8G("ngIf",t.expanded&&o.isExpandable(t))}}let se=(()=>{class i{constructor(){this.expanded=!0,this.depth=-1,this._currentDepth=0,this.segments=[]}ngOnChanges(){this.segments=[],this.json=this.decycle(this.json),"object"==typeof this.json?Object.keys(this.json).forEach(t=>{this.segments.push(this.parseKeyValue(t,this.json[t]))}):this.segments.push(this.parseKeyValue(`(${typeof this.json})`,this.json))}isExpandable(t){return"object"===t.type||"array"===t.type}toggle(t){this.isExpandable(t)&&(t.expanded=!t.expanded)}parseKeyValue(t,o){const n={key:t,value:o,type:void 0,description:""+o,expanded:this.isExpanded()};switch(typeof n.value){case"number":n.type="number";break;case"boolean":n.type="boolean";break;case"function":n.type="function";break;case"string":n.type="string",n.description='"'+n.value+'"';break;case"undefined":n.type="undefined",n.description="undefined";break;case"object":null===n.value?(n.type="null",n.description="null"):Array.isArray(n.value)?(n.type="array",n.description="Array["+n.value.length+"] "+JSON.stringify(n.value)):n.value instanceof Date?n.type="date":(n.type="object",n.description="Object "+JSON.stringify(n.value))}return n}isExpanded(){return this.expanded&&!(this.depth>-1&&this._currentDepth>=this.depth)}decycle(t){const o=new WeakMap;return function n(r,s){let a,d;return"object"!=typeof r||null===r||r instanceof Boolean||r instanceof Date||r instanceof Number||r instanceof RegExp||r instanceof String?r:(a=o.get(r),void 0!==a?{$ref:a}:(o.set(r,s),Array.isArray(r)?(d=[],r.forEach(function(p,F){d[F]=n(p,s+"["+F+"]")})):(d={},Object.keys(r).forEach(function(p){d[p]=n(r[p],s+"["+JSON.stringify(p)+"]")})),d))}(t,"$")}}return i.\u0275fac=function(t){return new(t||i)},i.\u0275cmp=e.VBU({type:i,selectors:[["ngx-json-viewer"]],inputs:{json:"json",expanded:"expanded",depth:"depth",_currentDepth:"_currentDepth"},features:[e.OA$],decls:2,vars:1,consts:[[1,"ngx-json-viewer"],[3,"ngClass",4,"ngFor","ngForOf"],[3,"ngClass"],[3,"click","ngClass"],["class","toggler",4,"ngIf"],[1,"segment-key"],[1,"segment-separator"],["class","segment-value",4,"ngIf"],["class","children",4,"ngIf"],[1,"toggler"],[1,"segment-value"],[1,"children"],[3,"json","expanded","depth","_currentDepth"]],template:function(t,o){1&t&&(e.j41(0,"section",0),e.DNE(1,Ye,9,11,"section",1),e.k0s()),2&t&&(e.R7$(),e.Y8G("ngForOf",o.segments))},dependencies:[h.YU,h.Sq,h.bT,i],styles:['@charset "UTF-8";.ngx-json-viewer[_ngcontent-%COMP%]{font-family:var(--ngx-json-font-family, monospace);font-size:var(--ngx-json-font-size, 1em);width:100%;height:100%;overflow:hidden;position:relative}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%]{padding:2px;margin:1px 1px 1px 12px}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%]{word-wrap:break-word}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .toggler[_ngcontent-%COMP%]{position:absolute;margin-left:-14px;margin-top:3px;font-size:.8em;line-height:1.2em;vertical-align:middle;color:var(--ngx-json-toggler, #787878)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .toggler[_ngcontent-%COMP%]:after{display:inline-block;content:"\\25ba";transition:transform .1s ease-in}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-key[_ngcontent-%COMP%]{color:var(--ngx-json-key, #4E187C)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-separator[_ngcontent-%COMP%]{color:var(--ngx-json-separator, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .segment-main[_ngcontent-%COMP%] .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-value, #000)}.ngx-json-viewer[_ngcontent-%COMP%] .segment[_ngcontent-%COMP%] .children[_ngcontent-%COMP%]{margin-left:12px}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-string[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-string, #FF6B6B)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-number[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-number, #009688)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-boolean[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-boolean, #B938A4)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-date[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-date, #05668D)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-array[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-array, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-object[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-object, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-function[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-function, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-null[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-null, #fff)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{color:var(--ngx-json-undefined, #fff)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-null[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{background-color:var(--ngx-json-null-bg, red)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-key[_ngcontent-%COMP%]{color:var(--ngx-json-undefined-key, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-undefined[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%] > .segment-value[_ngcontent-%COMP%]{background-color:var(--ngx-json-undefined-key, #999)}.ngx-json-viewer[_ngcontent-%COMP%] .segment-type-object[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%], .ngx-json-viewer[_ngcontent-%COMP%] .segment-type-array[_ngcontent-%COMP%] > .segment-main[_ngcontent-%COMP%]{white-space:nowrap}.ngx-json-viewer[_ngcontent-%COMP%] .expanded[_ngcontent-%COMP%] > .toggler[_ngcontent-%COMP%]:after{transform:rotate(90deg)}.ngx-json-viewer[_ngcontent-%COMP%] .expandable[_ngcontent-%COMP%], .ngx-json-viewer[_ngcontent-%COMP%] .expandable[_ngcontent-%COMP%] > .toggler[_ngcontent-%COMP%]{cursor:pointer}']}),i})(),qe=(()=>{class i{}return i.\u0275fac=function(t){return new(t||i)},i.\u0275mod=e.$C({type:i}),i.\u0275inj=e.G2t({imports:[h.MD]}),i})();var le=m(93331),V=m(38117),c=m(89417),He=m(28990),ze=m(96354),A=m(3366),v=m(19664),P=m(45794),I=m(97013);function Ue(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2,"\n "),e.j41(3,"b"),e.EFF(4,"Device name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"IEEE"),e.k0s(),e.EFF(8),e.j41(9,"b"),e.EFF(10,"Ep"),e.k0s(),e.EFF(11),e.j41(12,"b"),e.EFF(13,"Nwkid"),e.k0s(),e.EFF(14),e.k0s(),e.EFF(15,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t.IEEE," - "),e.R7$(3),e.SpI(" :\n ",t.Ep," - "),e.R7$(3),e.SpI(" : ",t.NwkId,"\n ")}}function Ke(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2,"\n "),e.j41(3,"b"),e.EFF(4,"Device name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"IEEE"),e.k0s(),e.EFF(8),e.j41(9,"b"),e.EFF(10,"Ep"),e.k0s(),e.EFF(11),e.j41(12,"b"),e.EFF(13,"Nwkid"),e.k0s(),e.EFF(14),e.k0s(),e.EFF(15,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t.IEEE," - "),e.R7$(3),e.SpI(" :\n ",t.Ep," - "),e.R7$(3),e.SpI(" : ",t.NwkId,"\n ")}}const Le=new V.Vy("BindingComponent");let We=(()=>{class i extends He.U{apiService;formBuilder;translate;toastr;form;clusters$;devicesSource;devicesTarget;devicesTargetFiltered;constructor(t,o,n,r){super(),this.apiService=t,this.formBuilder=o,this.translate=n,this.toastr=r}ngOnInit(){this.form=this.formBuilder.group({source:[null,c.k0.required],target:[null,c.k0.required],cluster:[null,c.k0.required]}),this.clusters$=this.apiService.getBindLSTcluster().pipe((0,ze.T)(t=>t.map(o=>(o.fullName=o.ClusterId+" "+o.ClusterDesc,o)))),this.subs.sink=this.form.get("cluster").valueChanges.subscribe(t=>{Le.debug("change:",t),this.apiService.getBindLSTdevice(this.form.get("cluster").value).subscribe(o=>{this.devicesSource=o,this.devicesTarget=o})})}filterDevices(t){this.form.get("target").patchValue(null),this.devicesTargetFiltered=this.devicesTarget.filter(o=>t.NwkId!==o.NwkId)}putBinding(){const t={sourceIeee:this.form.get("source").value.IEEE,sourceEp:this.form.get("source").value.Ep,destIeee:this.form.get("target").value.IEEE,destEp:this.form.get("target").value.Ep,cluster:this.form.get("cluster").value};this.apiService.putBinding(t).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.update.notify")),this.form.reset("",{onlySelf:!0,emitEvent:!1})})}putUnBinding(){const t={sourceIeee:this.form.get("source").value.IEEE,sourceEp:this.form.get("source").value.Ep,destIeee:this.form.get("target").value.IEEE,destEp:this.form.get("target").value.Ep,cluster:this.form.get("cluster").value};this.apiService.putUnBinding(t).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.update.notify")),this.form.reset("",{onlySelf:!0,emitEvent:!1})})}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$),e.rXU(P.tw))};static \u0275cmp=e.VBU({type:i,selectors:[["app-binding"]],features:[e.Vt3],decls:71,vars:26,consts:[[1,"row","row-cols-1","row-cols-xxl-3","row-cols-lg-2","row-cols-md-1","row-cols-sm-1","g-4"],[3,"formGroup"],[1,"card"],["translate","tools.binding.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["appendTo","body","bindLabel","fullName","bindValue","ClusterId","formControlName","cluster",3,"items","multiple","closeOnSelect","placeholder"],[1,"row","mt-2"],["appendTo","body","bindLabel","ZDeviceName","formControlName","source",3,"change","items","multiple","closeOnSelect","placeholder"],["ng-option-tmp",""],["bindLabel","ZDeviceName","appendTo","body","formControlName","target",3,"items","multiple","closeOnSelect","placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.binding.button.put",1,"btn","btn-primary",3,"click","disabled"],["translate","tools.unbinding.button.put",1,"ms-2","btn","btn-primary",3,"click","disabled"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"form",1),e.EFF(3,"\n "),e.j41(4,"div",2),e.EFF(5,"\n "),e.nrm(6,"div",3),e.EFF(7,"\n "),e.j41(8,"div",4),e.EFF(9,"\n "),e.nrm(10,"p",5),e.nI1(11,"translate"),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"div",8),e.EFF(18,"\n "),e.j41(19,"div"),e.EFF(20,"\n "),e.j41(21,"ng-select",9),e.nI1(22,"translate"),e.nI1(23,"async"),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.j41(29,"div",10),e.EFF(30,"\n "),e.j41(31,"div",8),e.EFF(32,"\n "),e.j41(33,"div"),e.EFF(34,"\n "),e.j41(35,"ng-select",11),e.nI1(36,"translate"),e.bIt("change",function(s){return n.filterDevices(s)}),e.EFF(37,"\n "),e.DNE(38,Ue,16,4,"ng-template",12),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.j41(44,"div",10),e.EFF(45,"\n "),e.j41(46,"div",8),e.EFF(47,"\n "),e.j41(48,"div"),e.EFF(49,"\n "),e.j41(50,"ng-select",13),e.nI1(51,"translate"),e.EFF(52,"\n "),e.DNE(53,Ke,16,4,"ng-template",12),e.EFF(54,"\n "),e.k0s(),e.EFF(55,"\n "),e.k0s(),e.EFF(56,"\n "),e.k0s(),e.EFF(57,"\n "),e.k0s(),e.EFF(58,"\n "),e.k0s(),e.EFF(59,"\n "),e.k0s(),e.EFF(60,"\n "),e.j41(61,"div",14),e.EFF(62,"\n "),e.j41(63,"button",15),e.bIt("click",function(){return n.putBinding()}),e.k0s(),e.EFF(64,"\n "),e.j41(65,"button",16),e.bIt("click",function(){return n.putUnBinding()}),e.k0s(),e.EFF(66,"\n "),e.k0s(),e.EFF(67,"\n "),e.k0s(),e.EFF(68,"\n "),e.k0s(),e.EFF(69,"\n"),e.k0s(),e.EFF(70,"\n")),2&o&&(e.R7$(2),e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(11,16,"tools.binding.subtitle"),e.npT),e.R7$(11),e.FS9("placeholder",e.bMT(22,18,"tools.binding.cluster")),e.Y8G("items",e.bMT(23,20,n.clusters$))("multiple",!1)("closeOnSelect",!0),e.R7$(14),e.FS9("placeholder",e.bMT(36,22,"tools.binding.sourceEp")),e.Y8G("items",n.devicesSource)("multiple",!1)("closeOnSelect",!0),e.R7$(15),e.FS9("placeholder",e.bMT(51,24,"tools.binding.destEp")),e.Y8G("items",n.devicesTargetFiltered)("multiple",!1)("closeOnSelect",!0),e.R7$(13),e.Y8G("disabled",!n.form.valid),e.R7$(2),e.Y8G("disabled",!n.form.valid))},dependencies:[c.qT,c.BC,c.cb,c.j4,c.JD,I.vr,I.Uq,v.Mm,h.Jj,v.D9]})}return i})();function Ze(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId,"")}}function Je(i,l){if(1&i){const t=e.RV6();e.j41(0,"ng-select",18),e.nI1(1,"translate"),e.bIt("change",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.setAction(n))}),e.EFF(2,"\n "),e.k0s()}if(2&i){const t=e.XpG();e.FS9("placeholder",e.bMT(1,5,"tools.debugcommand.action")),e.Y8G("items",t.capabilities.Capabilities)("multiple",!1)("closeOnSelect",!0)("searchable",!0)}}function Qe(i,l){if(1&i&&(e.j41(0,"ng-select",19),e.nI1(1,"translate"),e.EFF(2,"\n "),e.k0s()),2&i){const t=e.XpG();e.FS9("placeholder",e.bMT(1,5,"tools.debugcommand.type")),e.Y8G("items",t.capabilities.Types)("multiple",!1)("closeOnSelect",!0)("searchable",!0)}}function $e(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.j41(6,"span",20),e.mxI("colorPickerChange",function(n){e.eBV(t);const r=e.XpG();return e.DH7(r.colorPicker,n)||(r.colorPicker=n),e.Njj(n)}),e.k0s(),e.EFF(7,"\n "),e.k0s(),e.EFF(8,"\n "),e.k0s(),e.EFF(9,"\n "),e.k0s()}if(2&i){const t=e.XpG();e.R7$(6),e.xc7("background",t.colorPicker),e.Y8G("cpToggle",!0)("cpDialogDisplay","inline"),e.R50("colorPicker",t.colorPicker),e.Y8G("cpOutputFormat","rgba")}}function et(i,l){1&i&&e.nrm(0,"div",23)}function tt(i,l){if(1&i&&(e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.nrm(6,"input",21),e.nI1(7,"translate"),e.EFF(8,"\n "),e.DNE(9,et,1,0,"div",22),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(6),e.FS9("placeholder",e.bMT(7,2,"tools.debugcommand.value")),e.R7$(3),e.Y8G("ngIf",t.form.controls.effect.errors)}}function nt(i,l){1&i&&e.nrm(0,"div",26)}function ot(i,l){if(1&i&&(e.j41(0,"div",12),e.EFF(1,"\n "),e.j41(2,"div",7),e.EFF(3,"\n "),e.j41(4,"div"),e.EFF(5,"\n "),e.nrm(6,"input",24),e.nI1(7,"translate"),e.EFF(8,"\n "),e.DNE(9,nt,1,0,"div",25),e.EFF(10,"\n "),e.k0s(),e.EFF(11,"\n "),e.k0s(),e.EFF(12,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(6),e.FS9("placeholder",e.bMT(7,2,"tools.debugcommand.value")),e.R7$(3),e.Y8G("ngIf",!t.form.controls.level.valid)}}let it=(()=>{class i{toastr;apiService;formBuilder;translate;routers;capabilities;form;colorPicker="rgba(30,96,239,0.54)";capaSelected;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnInit(){this.form=this.formBuilder.group({level:[null,[c.k0.nullValidator,c.k0.min(0),c.k0.max(100)]],type:[null,c.k0.required],action:[null,c.k0.required],deviceSelected:[null,c.k0.required],effect:[null,c.k0.compose([c.k0.nullValidator,c.k0.pattern("^[0-9A-Fa-f]+")])]}),this.form.get("type").disable(),this.apiService.getZDevices().subscribe(t=>{this.routers=t.filter(o=>"Router"===o.LogicalType)})}callCapabilities(t){this.capaSelected=null,this.form.get("action").patchValue(null),this.form.get("type").patchValue(null),this.capabilities=null,this.apiService.getDevCap(t._NwkId).subscribe(o=>{this.capabilities=o})}setAction(t){this.capaSelected=t,this.form.get("type").patchValue(null),t&&!0===t.Type?this.form.get("type").enable():this.form.get("type").disable()}callAction(){let t=null,o=null;if(this.testRGB)if(this.colorPicker.startsWith("rgba")){let r=this.colorPicker.replace("rgba(","");r=r.replace(")","");const s=r.split(",");4===s.length&&(o=100*Number(s[3]),t="rgb("+s[0]+","+s[1]+","+s[2]+")")}else this.colorPicker.startsWith("rgb")&&(o=100,t=this.colorPicker);!o&&this.capaSelected.Value&&("hex"===this.capaSelected.Value&&(o=this.form.get("effect").value),"int"===this.capaSelected.Value&&(o=this.form.get("level").value));const n={NwkId:this.form.get("deviceSelected").value._NwkId,Command:this.form.get("action").value.actuator,Value:o,Color:t,Type:this.form.get("type").value};this.apiService.putDevCommand(n).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}get testRGB(){return!!this.form.get("type").value&&this.form.get("type").value.startsWith("ColorControl")}static \u0275fac=function(o){return new(o||i)(e.rXU(P.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-command"]],decls:61,vars:17,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.debugcommand.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["bindLabel","ZDeviceName","appendTo","body","formControlName","deviceSelected",3,"change","items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[1,"col-sm"],["translate","tools.debugcommand.button.cancel",1,"ms-3","btn","btn-secondary",3,"click"],[1,"row","mt-2"],["bindLabel","actuator","appendTo","body","formControlName","action",3,"items","multiple","closeOnSelect","searchable","placeholder","change",4,"ngIf"],["appendTo","body","formControlName","type",3,"items","multiple","closeOnSelect","searchable","placeholder",4,"ngIf"],["class","row mt-2",4,"ngIf"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.debugcommand.button.send",1,"btn","btn-primary",3,"click","disabled"],["bindLabel","actuator","appendTo","body","formControlName","action",3,"change","items","multiple","closeOnSelect","searchable","placeholder"],["appendTo","body","formControlName","type",3,"items","multiple","closeOnSelect","searchable","placeholder"],[3,"colorPickerChange","cpToggle","cpDialogDisplay","colorPicker","cpOutputFormat"],["type","text","formControlName","effect",1,"w-100","form-control",3,"placeholder"],["translate","tools.debugcommand.effect.error",4,"ngIf"],["translate","tools.debugcommand.effect.error"],["type","number","min","0","formControlName","level",1,"w-100","form-control",3,"placeholder"],["translate","tools.debugcommand.level.error",4,"ngIf"],["translate","tools.debugcommand.level.error"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"ng-select",8),e.nI1(18,"translate"),e.bIt("change",function(s){return n.callCapabilities(s)}),e.EFF(19,"\n "),e.DNE(20,Ze,10,2,"ng-template",9),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.j41(24,"div",10),e.EFF(25,"\n "),e.j41(26,"button",11),e.bIt("click",function(){return n.form.reset(),n.capaSelected=null}),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.j41(30,"div",12),e.EFF(31,"\n "),e.j41(32,"div",7),e.EFF(33,"\n "),e.DNE(34,Je,3,7,"ng-select",13),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.k0s(),e.EFF(37,"\n "),e.j41(38,"div",12),e.EFF(39,"\n "),e.j41(40,"div",7),e.EFF(41,"\n "),e.DNE(42,Qe,3,7,"ng-select",14),e.EFF(43,"\n "),e.k0s(),e.EFF(44,"\n "),e.k0s(),e.EFF(45,"\n "),e.DNE(46,$e,10,6,"div",15),e.EFF(47,"\n "),e.DNE(48,tt,13,4,"div",15),e.EFF(49,"\n "),e.DNE(50,ot,13,4,"div",15),e.EFF(51,"\n "),e.k0s(),e.EFF(52,"\n "),e.k0s(),e.EFF(53,"\n "),e.j41(54,"div",16),e.EFF(55,"\n "),e.j41(56,"button",17),e.bIt("click",function(){return n.callAction()}),e.k0s(),e.EFF(57,"\n "),e.k0s(),e.EFF(58,"\n "),e.k0s(),e.EFF(59,"\n"),e.k0s(),e.EFF(60,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,13,"tools.debugcommand.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(18,15,"tools.debugcommand.device")),e.Y8G("items",n.routers)("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(17),e.Y8G("ngIf",n.form.get("deviceSelected").value&&n.capabilities),e.R7$(8),e.Y8G("ngIf",n.capaSelected&&n.capaSelected.Type),e.R7$(4),e.Y8G("ngIf",n.capaSelected&&n.testRGB),e.R7$(2),e.Y8G("ngIf",n.capaSelected&&"hex"===n.capaSelected.Value),e.R7$(2),e.Y8G("ngIf",n.capaSelected&&"int"===n.capaSelected.Value),e.R7$(6),e.Y8G("disabled",!n.form.valid))},dependencies:[h.bT,c.qT,c.me,c.Q0,c.BC,c.cb,c.VZ,c.j4,c.JD,I.vr,I.Uq,v.Mm,Be,v.D9]})}return i})();function rt(i,l){1&i&&e.nrm(0,"div",14)}function st(i,l){1&i&&e.nrm(0,"div",14)}let lt=(()=>{class i{toastr;apiService;formBuilder;translate;form;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnInit(){this.form=this.formBuilder.group({Command:[null,c.k0.required],payload:[null]})}putCommand(){this.apiService.putCommandRaw(this.form.value).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}static \u0275fac=function(o){return new(o||i)(e.rXU(P.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-raw-command"]],decls:50,vars:13,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.rawcommand-zigate.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["type","text","formControlName","Command",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigate.error",4,"ngIf"],[1,"row","mt-2"],["type","text","formControlName","payload",1,"w-100","form-control",3,"placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.rawcommand-zigate.button.send",1,"btn","btn-primary",3,"click","disabled"],["translate","tools.rawcommand-zigate.error"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"div"),e.EFF(18,"\n "),e.nrm(19,"input",8),e.nI1(20,"translate"),e.EFF(21,"\n "),e.DNE(22,rt,1,0,"div",9),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.k0s(),e.EFF(26,"\n "),e.j41(27,"div",10),e.EFF(28,"\n "),e.j41(29,"div",7),e.EFF(30,"\n "),e.j41(31,"div"),e.EFF(32,"\n "),e.nrm(33,"input",11),e.nI1(34,"translate"),e.EFF(35,"\n "),e.DNE(36,st,1,0,"div",9),e.EFF(37,"\n "),e.k0s(),e.EFF(38,"\n "),e.k0s(),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.j41(43,"div",12),e.EFF(44,"\n "),e.j41(45,"button",13),e.bIt("click",function(){return n.putCommand()}),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.k0s(),e.EFF(48,"\n"),e.k0s(),e.EFF(49,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,7,"tools.rawcommand-zigate.subtitle"),e.npT),e.R7$(11),e.FS9("placeholder",e.bMT(20,9,"tools.rawcommand-zigate.command")),e.R7$(3),e.Y8G("ngIf",n.form.controls.Command.dirty&&!n.form.controls.Command.valid),e.R7$(11),e.FS9("placeholder",e.bMT(34,11,"tools.rawcommand-zigate.payload")),e.R7$(3),e.Y8G("ngIf",n.form.controls.payload.dirty&&!n.form.controls.payload.valid),e.R7$(9),e.Y8G("disabled",!n.form.valid))},dependencies:[h.bT,c.qT,c.me,c.BC,c.cb,c.j4,c.JD,v.Mm,v.D9]})}return i})();function at(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId," ")}}let ct=(()=>{class i{toastr;apiService;formBuilder;translate;devices$;form;constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}selectedCar;TrueFalse=[{id:!1,name:"False"},{id:!0,name:"True"}];ngOnInit(){this.form=this.formBuilder.group({ProfileId:["0104",c.k0.required],ClusterId:["0000",c.k0.required],TargetAddr:[null,c.k0.required],TargetEp:["01",c.k0.required],SourceEp:["01",c.k0.required],Sqn:["55",c.k0.required],Payload:[null,c.k0.required],GroupAddressFlag:[!1,c.k0.required],AckMode:[!1,c.k0.required]}),this.devices$=this.apiService.getZDeviceName()}putCommand(){this.apiService.putCommandRawZigpy(this.form.value).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.commandsent.notify"))})}static \u0275fac=function(o){return new(o||i)(e.rXU(P.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-raw-command-zigpy"]],decls:118,vars:34,consts:[[3,"formGroup"],[1,"card","h-100"],["translate","tools.rawcommand-zigpy.title",1,"card-header","fw-bold"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-6"],["bindLabel","ZDeviceName","bindValue","_NwkId","formControlName","TargetAddr",3,"items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[1,"row","mt-2"],["translate","tools.rawcommand-zigpy.groupaddressflag",1,"col-sm-3","col-form-label"],["bindLabel","name","bindValue","id","formControlName","GroupAddressFlag",3,"items"],["translate","tools.rawcommand-zigpy.ackmode",1,"col-sm-3","col-form-label"],["bindLabel","name","bindValue","id","formControlName","AckMode",3,"items"],["translate","tools.rawcommand-zigpy.profileid",1,"col-sm-3","col-form-label"],[1,"col-sm-2"],["type","text","formControlName","ProfileId",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.clusterid",1,"col-sm-3","col-form-label"],["type","text","formControlName","ClusterId",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.sourceep",1,"col-sm-3","col-form-label"],["type","text","formControlName","SourceEp",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.targetep",1,"col-sm-3","col-form-label"],["type","text","formControlName","TargetEp",1,"w-100","form-control",3,"placeholder"],["translate","tools.rawcommand-zigpy.sqn",1,"col-sm-3","col-form-label"],["type","text","formControlName","Sqn",1,"w-100","form-control",3,"placeholder"],[1,"col-sm"],["type","text","formControlName","Payload",1,"w-100","form-control",3,"placeholder"],[1,"card-footer","d-flex","justify-content-end"],["translate","tools.rawcommand-zigpy.button.send",1,"btn","btn-primary",3,"click","disabled"]],template:function(o,n){1&o&&(e.j41(0,"form",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.nrm(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7,"\n "),e.nrm(8,"p",4),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",5),e.EFF(12,"\n "),e.j41(13,"div",6),e.EFF(14,"\n "),e.j41(15,"div",7),e.EFF(16,"\n "),e.j41(17,"ng-select",8),e.nI1(18,"translate"),e.nI1(19,"async"),e.EFF(20,"\n "),e.DNE(21,at,10,2,"ng-template",9),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.k0s(),e.EFF(25,"\n "),e.j41(26,"div",10),e.EFF(27,"\n "),e.nrm(28,"label",11),e.EFF(29,"\n "),e.j41(30,"div",7),e.EFF(31,"\n "),e.j41(32,"ng-select",12),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.k0s(),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.j41(37,"div",10),e.EFF(38,"\n "),e.nrm(39,"label",13),e.EFF(40,"\n "),e.j41(41,"div",7),e.EFF(42,"\n "),e.j41(43,"ng-select",14),e.EFF(44," "),e.k0s(),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.j41(48,"div",10),e.EFF(49,"\n "),e.nrm(50,"label",15),e.EFF(51,"\n "),e.j41(52,"div",16),e.EFF(53,"\n "),e.nrm(54,"input",17),e.nI1(55,"translate"),e.EFF(56,"\n "),e.k0s(),e.EFF(57,"\n "),e.nrm(58,"label",18),e.EFF(59,"\n "),e.j41(60,"div",16),e.EFF(61,"\n "),e.nrm(62,"input",19),e.nI1(63,"translate"),e.EFF(64,"\n "),e.k0s(),e.EFF(65,"\n "),e.k0s(),e.EFF(66,"\n "),e.j41(67,"div",10),e.EFF(68,"\n "),e.nrm(69,"label",20),e.EFF(70,"\n "),e.j41(71,"div",16),e.EFF(72,"\n "),e.nrm(73,"input",21),e.nI1(74,"translate"),e.EFF(75,"\n "),e.k0s(),e.EFF(76,"\n "),e.nrm(77,"label",22),e.EFF(78,"\n "),e.j41(79,"div",16),e.EFF(80,"\n "),e.nrm(81,"input",23),e.nI1(82,"translate"),e.EFF(83,"\n "),e.k0s(),e.EFF(84,"\n "),e.k0s(),e.EFF(85,"\n "),e.j41(86,"div",10),e.EFF(87,"\n "),e.nrm(88,"label",24),e.EFF(89,"\n "),e.j41(90,"div",16),e.EFF(91,"\n "),e.j41(92,"div"),e.EFF(93,"\n "),e.nrm(94,"input",25),e.nI1(95,"translate"),e.EFF(96,"\n "),e.k0s(),e.EFF(97,"\n "),e.k0s(),e.EFF(98,"\n "),e.k0s(),e.EFF(99,"\n "),e.j41(100,"div",10),e.EFF(101,"\n "),e.j41(102,"div",26),e.EFF(103,"\n "),e.nrm(104,"input",27),e.nI1(105,"translate"),e.EFF(106,"\n "),e.k0s(),e.EFF(107,"\n "),e.k0s(),e.EFF(108,"\n "),e.k0s(),e.EFF(109,"\n "),e.k0s(),e.EFF(110,"\n "),e.j41(111,"div",28),e.EFF(112,"\n "),e.j41(113,"button",29),e.bIt("click",function(){return n.putCommand()}),e.k0s(),e.EFF(114,"\n "),e.k0s(),e.EFF(115,"\n "),e.k0s(),e.EFF(116,"\n"),e.k0s(),e.EFF(117,"\n")),2&o&&(e.Y8G("formGroup",n.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,16,"tools.rawcommand-zigpy.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(18,18,"tools.rawcommand-zigpy.placeholder")),e.Y8G("items",e.bMT(19,20,n.devices$))("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(15),e.Y8G("items",n.TrueFalse),e.R7$(11),e.Y8G("items",n.TrueFalse),e.R7$(11),e.FS9("placeholder",e.bMT(55,22,"tools.rawcommand-zigpy.profileid")),e.R7$(8),e.FS9("placeholder",e.bMT(63,24,"tools.rawcommand-zigpy.clusterid")),e.R7$(11),e.FS9("placeholder",e.bMT(74,26,"tools.rawcommand-zigpy.sourceep")),e.R7$(8),e.FS9("placeholder",e.bMT(82,28,"tools.rawcommand-zigpy.targetep")),e.R7$(13),e.FS9("placeholder",e.bMT(95,30,"tools.rawcommand-zigpy.sqn")),e.R7$(10),e.FS9("placeholder",e.bMT(105,32,"tools.rawcommand-zigpy.payload")),e.R7$(9),e.Y8G("disabled",!n.form.valid))},dependencies:[c.qT,c.me,c.BC,c.cb,c.j4,c.JD,I.vr,I.Uq,v.Mm,h.Jj,v.D9]})}return i})();function pt(i,l){1&i&&e.nrm(0,"app-raw-command")}function dt(i,l){1&i&&e.nrm(0,"app-raw-command-zigpy")}let ut=(()=>{class i{plugin;ngOnInit(){setTimeout(()=>{this.plugin=JSON.parse(sessionStorage.getItem("plugin"))},500)}static \u0275fac=function(o){return new(o||i)};static \u0275cmp=e.VBU({type:i,selectors:[["app-command"]],decls:9,vars:2,consts:[[1,"row","row-cols-1","row-cols-xxl-3","row-cols-lg-2","row-cols-md-1","row-cols-sm-1","g-4"],[4,"ngIf"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.nrm(2,"app-debug-command"),e.EFF(3,"\n "),e.DNE(4,pt,1,0,"app-raw-command",1),e.EFF(5,"\n "),e.DNE(6,dt,1,0,"app-raw-command-zigpy",1),e.EFF(7,"\n"),e.k0s(),e.EFF(8,"\n")),2&o&&(e.R7$(4),e.Y8G("ngIf",!(null!=n.plugin&&n.plugin.Zigpy)),e.R7$(2),e.Y8G("ngIf",null==n.plugin?null:n.plugin.Zigpy))},dependencies:[h.bT,it,lt,ct]})}return i})();var gt=m(88652),ae=m(38852);function mt(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",5),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function ht(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",6),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function ft(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",7),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function vt(i,l){if(1&i&&(e.j41(0,"div",3),e.EFF(1,"\n "),e.nrm(2,"label",4),e.EFF(3,"\n "),e.nrm(4,"input",5),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("translate",t.setting.Name)}}function Ct(i,l){if(1&i&&(e.j41(0,"div",8),e.EFF(1,"\n "),e.nrm(2,"input",9),e.EFF(3,"\n "),e.nrm(4,"label",10),e.EFF(5,"\n "),e.k0s()),2&i){const t=e.XpG();e.R7$(2),e.FS9("id",t.setting.Name),e.R7$(2),e.FS9("for",t.setting.Name),e.FS9("translate",t.setting.Name)}}let Ft=(()=>{class i{formBuilder;fgd;setting;advanced;constructor(t,o){this.formBuilder=t,this.fgd=o}ngOnInit(){let t;t=this.formBuilder.group("hex"===this.setting.DataType?{current:["",c.k0.compose([c.k0.required,c.k0.pattern("^[0-9A-Fa-f]+")])]}:"bool"===this.setting.DataType?{current:[]}:{current:["",c.k0.required]}),this.fgd.form.addControl(this.setting.Name,t);const o=""!==this.setting.current_value?this.setting.current_value:this.setting.default_value;this.fgd.form.get(this.setting.Name).get("current").patchValue(o)}static \u0275fac=function(o){return new(o||i)(e.rXU(c.ok),e.rXU(c.j4))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-setting"]],inputs:{setting:"setting",advanced:"advanced"},features:[e.Jv_([],[{provide:c.ZU,useExisting:c.j4}])],decls:13,vars:6,consts:[[3,"formGroupName"],["class","d-flex flex-row align-items-center flex-wrap mt-2",4,"ngIf"],["class","form-check form-check-inline mt-2",4,"ngIf"],[1,"d-flex","flex-row","align-items-center","flex-wrap","mt-2"],["for","current",1,"me-2",3,"translate"],["type","text","formControlName","current",1,"w-25","form-control"],["type","text","formControlName","current",1,"w-100","form-control"],["type","number","formControlName","current",1,"form-control","w-25"],[1,"form-check","form-check-inline","mt-2"],["formControlName","current","type","checkbox",1,"form-check-input",3,"id"],[1,"form-check-label",3,"for","translate"]],template:function(o,n){1&o&&(e.qex(0,0),e.EFF(1,"\n "),e.DNE(2,mt,6,1,"div",1),e.EFF(3,"\n "),e.DNE(4,ht,6,1,"div",1),e.EFF(5,"\n "),e.DNE(6,ft,6,1,"div",1),e.EFF(7,"\n "),e.DNE(8,vt,6,1,"div",1),e.EFF(9,"\n "),e.DNE(10,Ct,6,3,"div",2),e.EFF(11,"\n"),e.bVm(),e.EFF(12,"\n")),2&o&&(e.Y8G("formGroupName",n.setting.Name),e.R7$(2),e.Y8G("ngIf","str"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","path"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","int"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","hex"===n.setting.DataType),e.R7$(2),e.Y8G("ngIf","bool"===n.setting.DataType))},dependencies:[h.bT,c.me,c.Q0,c.Zm,c.BC,c.cb,c.JD,c.$R,v.Mm],styles:["was-validated[_ngcontent-%COMP%] .custom-control-input[_ngcontent-%COMP%]:valid ~ .custom-control-label[_ngcontent-%COMP%], .custom-control-input.is-valid[_ngcontent-%COMP%] ~ .custom-control-label[_ngcontent-%COMP%]{color:#000}"]})}return i})();const $=["contentRestart"];function _t(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function bt(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,_t,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit;e.R7$(2),e.Y8G("ngIf",!t.Advanced&&"bool"===t.DataType)}}function kt(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function Et(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,kt,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit;e.R7$(2),e.Y8G("ngIf",!t.Advanced&&"bool"!==t.DataType)}}function yt(i,l){if(1&i&&e.nrm(0,"app-debug-setting",29),2&i){const t=e.XpG().$implicit,o=e.XpG(4);e.Y8G("setting",t)("advanced",o.advanced)}}function xt(i,l){if(1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,yt,1,2,"app-debug-setting",28),e.EFF(3,"\n "),e.bVm()),2&i){const t=l.$implicit,o=e.XpG(4);e.R7$(2),e.Y8G("ngIf",t.Advanced&&t.Advanced===o.advanced)}}function wt(i,l){if(1&i&&(e.j41(0,"div",21),e.EFF(1,"\n "),e.nrm(2,"div",22),e.EFF(3,"\n "),e.j41(4,"div",23),e.EFF(5,"\n "),e.j41(6,"div",24),e.EFF(7,"\n "),e.nrm(8,"p",25),e.EFF(9,"\n "),e.k0s(),e.EFF(10,"\n "),e.j41(11,"div",24),e.EFF(12,"\n "),e.j41(13,"div",26),e.EFF(14,"\n "),e.DNE(15,bt,4,1,"ng-container",19),e.EFF(16,"\n "),e.k0s(),e.EFF(17,"\n "),e.j41(18,"div",27),e.EFF(19,"\n "),e.DNE(20,Et,4,1,"ng-container",19),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"div",27),e.EFF(24,"\n "),e.DNE(25,xt,4,1,"ng-container",19),e.EFF(26,"\n "),e.k0s(),e.EFF(27,"\n "),e.k0s(),e.EFF(28,"\n "),e.k0s(),e.EFF(29,"\n "),e.k0s()),2&i){const t=e.XpG().$implicit,o=e.XpG(2);e.R7$(2),e.Y8G("innerHTML",o.getTranslation("setting.header.",t._Theme),e.npT),e.R7$(6),e.Y8G("innerHTML",o.getTranslation("setting.subtitle.",t._Theme),e.npT),e.R7$(7),e.Y8G("ngForOf",t.ListOfSettings),e.R7$(5),e.Y8G("ngForOf",t.ListOfSettings),e.R7$(5),e.Y8G("ngForOf",t.ListOfSettings)}}function jt(i,l){if(1&i&&(e.j41(0,"div"),e.EFF(1,"\n "),e.DNE(2,wt,30,5,"div",20),e.EFF(3,"\n "),e.k0s()),2&i){const t=l.$implicit,o=e.XpG(2);e.R7$(2),e.Y8G("ngIf",o.hasBasicSettings(t.ListOfSettings))}}function At(i,l){if(1&i){const t=e.RV6();e.j41(0,"form",4),e.EFF(1,"\n "),e.j41(2,"fieldset",5),e.EFF(3,"\n "),e.j41(4,"legend"),e.EFF(5,"\n "),e.j41(6,"div",6),e.EFF(7,"\n "),e.nrm(8,"h5",7),e.nI1(9,"translate"),e.EFF(10,"\n "),e.j41(11,"div",8),e.EFF(12,"\n "),e.j41(13,"div",9),e.EFF(14,"\n "),e.j41(15,"div",10),e.EFF(16,"\n "),e.j41(17,"button",11),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.updateSettings())}),e.k0s(),e.EFF(18,"\n "),e.k0s(),e.EFF(19,"\n "),e.j41(20,"div",12),e.EFF(21,"\n "),e.j41(22,"button",13),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.reinitSettings())}),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.j41(25,"div",14),e.EFF(26,"\n "),e.j41(27,"input",15),e.bIt("click",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.advancedSettings(n))}),e.k0s(),e.EFF(28,"\n "),e.nrm(29,"label",16),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n "),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n "),e.k0s(),e.EFF(34,"\n "),e.k0s(),e.EFF(35,"\n "),e.k0s(),e.EFF(36,"\n "),e.j41(37,"div",17),e.EFF(38,"\n "),e.j41(39,"div",18),e.EFF(40,"\n "),e.DNE(41,jt,4,1,"div",19),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.k0s(),e.EFF(44,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("formGroup",t.form),e.R7$(8),e.Y8G("innerHTML",e.bMT(9,5,"tools.debugsetting.help.legend"),e.npT),e.R7$(9),e.Y8G("disabled",!t.form.valid),e.R7$(10),e.Y8G("checked",t.advanced),e.R7$(14),e.Y8G("ngForOf",t.settings)}}function Tt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",31),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",33),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",35),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}function It(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",36),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",37),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",38),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}function St(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"div",30),e.EFF(2,"\n "),e.nrm(3,"h4",39),e.EFF(4,"\n "),e.j41(5,"button",32),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("Cross click"))}),e.k0s(),e.EFF(6,"\n "),e.k0s(),e.EFF(7,"\n "),e.nrm(8,"div",40),e.EFF(9,"\n "),e.j41(10,"div",34),e.EFF(11,"\n "),e.j41(12,"button",41),e.bIt("click",function(){const n=e.eBV(t).$implicit;return e.Njj(n.dismiss("cancel"))}),e.k0s(),e.EFF(13,"\n "),e.k0s(),e.EFF(14,"\n")}}let Rt=(()=>{class i{modalService;apiService;formBuilder;toastr;headerService;translate;contentRestart;contentReset;contentErase;form;settings;advanced=!1;constructor(t,o,n,r,s,a){this.modalService=t,this.apiService=o,this.formBuilder=n,this.toastr=r,this.headerService=s,this.translate=a}ngOnInit(){this.form=this.formBuilder.group({}),this.apiService.getSettingsDebug().subscribe(t=>{this.settings=t,this.settings[0].ListOfSettings.sort((o,n)=>o.Name.localeCompare(n.Name))})}reinitSettings(){this.settings.forEach(t=>{const o=[];t.ListOfSettings.forEach(n=>{n.current_value=n.default_value,o.push(Object.assign({},n))}),t.ListOfSettings=o}),this.settings=[...this.settings]}advancedSettings(t){this.advanced=!!t.currentTarget.checked}updateSettings(){this.form.invalid?this.form.markAsTouched():(Object.keys(this.form.value).forEach(t=>{!0===this.form.value[t].current?this.form.value[t].current=1:!1===this.form.value[t].current&&(this.form.value[t].current=0)}),this.apiService.putSettingsDebug(this.form.value).subscribe(()=>{this.form.markAsPristine(),this.toastr.success(this.translate.instant("api.global.succes.saved.notify")),this.apiService.getSettingsDebug().subscribe(t=>{this.settings=t,this.settings[0].ListOfSettings.sort((o,n)=>o.Name.localeCompare(n.Name))}),this.apiService.getRestartNeeded().subscribe(t=>{1===t.RestartNeeded?(this.headerService.setRestart(!0),this.open(this.contentRestart)):2===t.RestartNeeded?this.open(this.contentReset):3===t.RestartNeeded&&this.open(this.contentErase)})}))}open(t){this.modalService.open(t,{ariaLabelledBy:"modal-basic-title"}).result.then()}hasBasicSettings(t){return!!this.advanced||t.filter(o=>!1===o.Advanced).length>0}getTranslation(t,o){return this.translate.instant(t.concat(o))}static \u0275fac=function(o){return new(o||i)(e.rXU(gt.Bq),e.rXU(A.G),e.rXU(c.ok),e.rXU(P.tw),e.rXU(ae.d),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-debug-settings"]],viewQuery:function(o,n){if(1&o&&(e.GBs($,5),e.GBs($,5),e.GBs($,5)),2&o){let r;e.mGM(r=e.lsd())&&(n.contentRestart=r.first),e.mGM(r=e.lsd())&&(n.contentReset=r.first),e.mGM(r=e.lsd())&&(n.contentErase=r.first)}},decls:11,vars:1,consts:[["contentRestart",""],["contentReset",""],["contentErase",""],[3,"formGroup",4,"ngIf"],[3,"formGroup"],[1,"h-100"],[1,"row"],[1,"col-sm-8",3,"innerHTML"],[1,"col-sm-4"],[1,"d-flex","flex-row-reverse","align-items-center"],[1,"p-2"],["translate","tools.debugsetting.validate.button",1,"btn","btn-primary",3,"click","disabled"],[1,"p-2","ms-3"],["translate","tools.debugsetting.reinit.button",1,"btn","btn-secondary",3,"click"],[1,"switch","switch-sm","me-2","pr-2","float-right"],["type","checkbox","id","switch-advanced",1,"switch",3,"click","checked"],["for","switch-advanced","translate","tools.debugsetting.advanced.button",1,"mb-0"],[1,"row","row-cols-1","row-cols-sm-1","g-4"],[1,"col"],[4,"ngFor","ngForOf"],["class","card",4,"ngIf"],[1,"card"],[1,"card-header","fw-bold",3,"innerHTML"],[1,"card-body"],[1,"card-text"],[3,"innerHTML"],[1,"row","row-cols-1","row-cols-xl-6","row-cols-md-3","row-cols-sm-1","align-items-center"],[1,"row","row-cols-1","row-cols-xl-6","row-cols-md-3","row-cols-sm-1","align-items-center","mt-2"],[3,"setting","advanced",4,"ngIf"],[3,"setting","advanced"],[1,"modal-header"],["id","modal-basic-title","translate","setting.reloadplugin.alert.title",1,"modal-title"],["type","button","aria-label","Close",1,"btn-close",3,"click"],["translate","setting.reloadplugin.alert.subject",1,"modal-body"],[1,"modal-footer"],["type","button","translate","setting.reloadplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","setting.resetplugin.alert.title",1,"modal-title"],["translate","setting.resetplugin.alert.subject",1,"modal-body"],["type","button","translate","setting.resetplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"],["id","modal-basic-title","translate","setting.eraseplugin.alert.title",1,"modal-title"],["translate","setting.eraseplugin.alert.subject",1,"modal-body"],["type","button","translate","setting.eraseplugin.alert.cancel",1,"btn","btn-outline-dark",3,"click"]],template:function(o,n){1&o&&(e.DNE(0,At,45,7,"form",3),e.EFF(1,"\n\n"),e.DNE(2,Tt,15,0,"ng-template",null,0,e.C5r),e.EFF(4,"\n\n"),e.DNE(5,It,15,0,"ng-template",null,1,e.C5r),e.EFF(7,"\n\n"),e.DNE(8,St,15,0,"ng-template",null,2,e.C5r),e.EFF(10,"\n")),2&o&&e.Y8G("ngIf",n.settings)},dependencies:[h.Sq,h.bT,c.qT,c.cb,c.j4,v.Mm,Ft,v.D9],styles:[".btn-secondary[_ngcontent-%COMP%]{--bs-btn-color: white}"]})}return i})();var ce=m(70980);function pe(i,l){const t=new h.vh("en-US");if("LastSeen"===i)return t.transform(1e3*l,"dd/MM/yyyy HH:mm:ss");if(["TimeStamps","TimeStamp","Stamp","Time","StartTime","BatteryUpdateTime","TargetTime","BatteryPercentage_TimeStamp","BatteryVoltage_TimeStamp","BatteryPercentage_TimeStamp","PairingTime"].indexOf(i)>-1){if(l>0){let n=1e3*l;return n=Number(n.toFixed(0)),t.transform(n,"dd/MM/yyyy HH:mm:ss")}return l}return l}function Bt(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",4),e.EFF(1,"\n "),e.j41(2,"button",5),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.export(n.json))}),e.k0s(),e.EFF(3,"\n\n "),e.nrm(4,"ngx-json-viewer",6),e.EFF(5,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("hidden",t.isLoading),e.R7$(4),e.Y8G("expanded",!1)("json",t.json)}}let Vt=(()=>{class i{apiService;headerService;fileSaverService;json=null;isLoading=!1;constructor(t,o,n){this.apiService=t,this.headerService=o,this.fileSaverService=n}onClick(t){let o;this.json=null,"log-error-history"===t&&(o=this.apiService.getLogErrorHistory(),this.headerService.setError(!1)),"clear-error-history"===t&&(o=this.apiService.clearLogErrorHistory(),this.headerService.setError(!1)),o&&o.pipe((0,ce.j)(()=>{this.isLoading=!1})).subscribe(n=>{this.callbackservice(n)})}callbackservice(t){const o=JSON.stringify(t);this.json=JSON.parse(o,pe)}export(t){const o="errors.json",n=this.fileSaverService.genType(o),r=new Blob([JSON.stringify(t)],{type:n});this.fileSaverService.save(r,o)}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(ae.d),e.rXU(re))};static \u0275cmp=e.VBU({type:i,selectors:[["app-error"]],decls:9,vars:1,consts:[[1,"row","d-flex","ms-2","gap-2"],["translate","tools.error.log-history.button",1,"col-xl-2","col-lg-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.error.log-history.clear",1,"col-xl-2","col-lg-4","col-sm-5","btn","btn-primary",3,"click"],["class","row ms-2 mt-2",3,"hidden",4,"ngIf"],[1,"row","ms-2","mt-2",3,"hidden"],["translate","tools.tools.export",1,"col-lg-1","mb-2","btn","btn-primary",3,"click"],[3,"expanded","json"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"button",1),e.bIt("click",function(){return n.onClick("log-error-history")}),e.k0s(),e.EFF(3,"\n "),e.j41(4,"button",2),e.bIt("click",function(){return n.onClick("clear-error-history")}),e.k0s(),e.EFF(5,"\n"),e.k0s(),e.EFF(6,"\n"),e.DNE(7,Bt,6,3,"div",3),e.EFF(8,"\n")),2&o&&(e.R7$(7),e.Y8G("ngIf",n.json))},dependencies:[h.bT,v.Mm,se]})}return i})();var Pt=m(34402),ee=m(46247),Dt=m(5779),Mt=m(22242);const Gt=()=>[10,25,50];function Nt(i,l){1&i&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"th",5),e.EFF(4),e.nI1(5,"translate"),e.k0s(),e.EFF(6,"\n "),e.j41(7,"th",6),e.EFF(8),e.nI1(9,"translate"),e.k0s(),e.EFF(10,"\n "),e.j41(11,"th",7),e.EFF(12),e.nI1(13,"translate"),e.k0s(),e.EFF(14,"\n "),e.j41(15,"th",7),e.EFF(16),e.nI1(17,"translate"),e.k0s(),e.EFF(18,"\n "),e.j41(19,"th",7),e.EFF(20),e.nI1(21,"translate"),e.k0s(),e.EFF(22,"\n "),e.j41(23,"th",7),e.EFF(24),e.nI1(25,"translate"),e.k0s(),e.EFF(26,"\n "),e.j41(27,"th",8),e.EFF(28),e.nI1(29,"translate"),e.k0s(),e.EFF(30,"\n "),e.k0s(),e.EFF(31,"\n ")),2&i&&(e.R7$(4),e.JRh(e.bMT(5,7,"tools.reporting.configure.clusterId.column")),e.R7$(4),e.JRh(e.bMT(9,9,"tools.reporting.configure.attributeId.column")),e.R7$(4),e.JRh(e.bMT(13,11,"tools.reporting.configure.dataType.column")),e.R7$(4),e.JRh(e.bMT(17,13,"tools.reporting.configure.timeout.column")),e.R7$(4),e.JRh(e.bMT(21,15,"tools.reporting.configure.minInterval.column")),e.R7$(4),e.JRh(e.bMT(25,17,"tools.reporting.configure.maxInterval.column")),e.R7$(4),e.JRh(e.bMT(29,19,"tools.reporting.configure.change.column")))}function Ot(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MinInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.minInterval)}}function Xt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MinInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.minInterval)}}function Yt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MaxInterval",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.maxInterval)}}function qt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG().$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"MaxInterval",r))}),e.k0s(),e.EFF(2," ")}if(2&i){const t=e.XpG().$implicit;e.R7$(),e.Y8G("value",t.maxInterval)}}function Ht(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG(2).$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"Change",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG(2).$implicit;e.R7$(),e.Y8G("value",t.change)}}function zt(i,l){if(1&i){const t=e.RV6();e.EFF(0,"\n "),e.j41(1,"input",15),e.bIt("change",function(n){e.eBV(t);const r=e.XpG(2).$implicit,s=e.XpG();return e.Njj(s.updateValue(n,"Change",r))}),e.k0s(),e.EFF(2,"\n ")}if(2&i){const t=e.XpG(2).$implicit;e.R7$(),e.Y8G("value",t.change)}}function Ut(i,l){1&i&&(e.qex(0),e.EFF(1,"\n "),e.DNE(2,Ht,3,1,"ng-template",10),e.EFF(3,"\n "),e.DNE(4,zt,3,1,"ng-template",11),e.EFF(5,"\n "),e.bVm())}function Kt(i,l){if(1&i&&e.EFF(0),2&i){const t=e.XpG().$implicit;e.JRh(t.change)}}function Lt(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"tr"),e.EFF(2,"\n "),e.j41(3,"td"),e.EFF(4),e.k0s(),e.EFF(5,"\n "),e.j41(6,"td"),e.EFF(7),e.k0s(),e.EFF(8,"\n "),e.j41(9,"td"),e.EFF(10),e.k0s(),e.EFF(11,"\n "),e.j41(12,"td"),e.EFF(13),e.k0s(),e.EFF(14,"\n "),e.j41(15,"td",9),e.EFF(16,"\n "),e.j41(17,"p-cellEditor"),e.EFF(18,"\n "),e.DNE(19,Ot,3,1,"ng-template",10),e.EFF(20,"\n "),e.DNE(21,Xt,3,1,"ng-template",11),e.EFF(22,"\n "),e.k0s(),e.EFF(23,"\n "),e.k0s(),e.EFF(24,"\n "),e.j41(25,"td",12),e.EFF(26,"\n "),e.j41(27,"p-cellEditor"),e.EFF(28,"\n "),e.DNE(29,Yt,3,1,"ng-template",10),e.EFF(30,"\n "),e.DNE(31,qt,3,1,"ng-template",11),e.k0s(),e.EFF(32,"\n "),e.k0s(),e.EFF(33,"\n "),e.j41(34,"td",13),e.EFF(35,"\n "),e.j41(36,"p-cellEditor"),e.EFF(37,"\n "),e.DNE(38,Ut,6,0,"ng-container",14),e.EFF(39,"\n "),e.DNE(40,Kt,1,1,"ng-template",null,1,e.C5r),e.k0s(),e.EFF(42,"\n "),e.k0s(),e.EFF(43,"\n "),e.k0s()),2&i){const t=l.$implicit,o=e.sdS(41),n=e.XpG();e.R7$(4),e.JRh(t.clusterId),e.R7$(3),e.JRh(t.attributeId),e.R7$(3),e.JRh(t.dataType),e.R7$(3),e.JRh(t.timeOut),e.R7$(2),e.Y8G("pEditableColumn",t.minInterval),e.R7$(10),e.Y8G("pEditableColumn",t.maxInterval),e.R7$(9),e.Y8G("pEditableColumn",t.change),e.R7$(4),e.Y8G("ngIf",n.isEditable(t))("ngIfElse",o)}}let Wt=(()=>{class i{toastr;apiService;formBuilder;translate;clusters;clustersChange=new e.bkB;clustersToDisplay=[];datatypeConvertor=[{type:"10",longueur:"0",editable:!1},{type:"20",longueur:"0",editable:!0},{type:"21",longueur:"00",editable:!0},{type:"22",longueur:"000",editable:!0},{type:"23",longueur:"0000",editable:!0},{type:"24",longueur:"00000",editable:!0},{type:"25",longueur:"000000",editable:!0},{type:"26",longueur:"0000000",editable:!0},{type:"27",longueur:"00000000",editable:!0},{type:"28",longueur:"0",editable:!0},{type:"29",longueur:"00",editable:!0},{type:"2a",longueur:"000",editable:!0},{type:"2b",longueur:"0000",editable:!0},{type:"2c",longueur:"00000",editable:!0},{type:"2d",longueur:"000000",editable:!0},{type:"2e",longueur:"0000000",editable:!0},{type:"2f",longueur:"00000000",editable:!0},{type:"38",longueur:"00",editable:!0},{type:"39",longueur:"0000",editable:!0},{type:"3a",longueur:"00000000",editable:!0},{type:"e0",longueur:"0000",editable:!0},{type:"e1",longueur:"0000",editable:!0},{type:"e2",longueur:"0000",editable:!0}];constructor(t,o,n,r){this.toastr=t,this.apiService=o,this.formBuilder=n,this.translate=r}ngOnChanges(t){t.clusters.currentValue&&this.formatClusters(t.clusters.currentValue)}formatClusters(t){this.clustersToDisplay=[],t.forEach(o=>{o.Attributes.forEach(n=>{n.Infos.forEach(r=>{const s=new Pt.E0;s.clusterId=o.ClusterId,s.attributeId=n.Attribute,s.change=parseInt(r.Change,16).toString(),s.dataType=r.DataType,s.maxInterval=parseInt(r.MaxInterval,16).toString(),s.minInterval=parseInt(r.MinInterval,16).toString(),s.timeOut=parseInt(r.TimeOut,16).toString(),this.clustersToDisplay.push(s)})})})}updateValue(t,o,n){const r=t.target.value,s=this.clusters.find(a=>a.ClusterId===n.clusterId).Attributes.find(a=>a.Attribute===n.attributeId).Infos[0];if(!this.controlerValue(Number(r),o,s)){if("Change"===o){const a=this.datatypeConvertor.find(d=>d.type===s.DataType);s[o]=(a.longueur+Number(r).toString(16).toUpperCase()).slice(-a.longueur.length)}else s[o]=Number(r).toString(16).toUpperCase();this.formatClusters(this.clusters),this.clustersChange.emit(this.clusters)}}controlerValue(t,o,n){let r=!1;if(isNaN(t))r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.hexa.error"));else if("Change"!==o&&Number(t)>65535)r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error"));else if("Change"===o){const s=this.datatypeConvertor.find(d=>d.type===n.DataType),a=s.longueur.split("0").join("F");Number(t)>parseInt(a,16)&&(r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error"))),"10"===s.type&&Number(t)>1&&(r=!0,this.clustersChange.emit(null),alert(this.translate.instant("reporting.configure.length.error")))}return r}isEditable(t){const o=this.datatypeConvertor.find(n=>n.type===t.dataType);return o&&o.editable}static \u0275fac=function(o){return new(o||i)(e.rXU(P.tw),e.rXU(A.G),e.rXU(c.ok),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-configure-cluster-reporting"]],inputs:{clusters:"clusters"},outputs:{clustersChange:"clustersChange"},features:[e.OA$],decls:9,vars:11,consts:[["dt1",""],["notEditable",""],["responsiveLayout","scroll","stateStorage","local","stateKey","cluster",3,"rowHover","showCurrentPageReport","currentPageReportTemplate","rowsPerPageOptions","value","rows","paginator","scrollable"],["pTemplate","header"],["pTemplate","body"],[2,"width","15rem"],[2,"width","7rem"],[2,"width","5rem"],[2,"width","3rem"],["pEditableColumnField","minInterval",3,"pEditableColumn"],["pTemplate","input"],["pTemplate","output"],["pEditableColumnField","maxInterval",3,"pEditableColumn"],["pEditableColumnField","change",3,"pEditableColumn"],[4,"ngIf","ngIfElse"],["pInputText","","type","text",3,"change","value"]],template:function(o,n){1&o&&(e.j41(0,"p-table",2,0),e.nI1(2,"translate"),e.EFF(3,"\n "),e.DNE(4,Nt,32,21,"ng-template",3),e.EFF(5,"\n "),e.DNE(6,Lt,44,9,"ng-template",4),e.EFF(7,"\n"),e.k0s(),e.EFF(8,"\n")),2&o&&(e.FS9("currentPageReportTemplate",e.bMT(2,8,"TOTAL")),e.Y8G("rowHover",!0)("showCurrentPageReport",!0)("rowsPerPageOptions",e.lJ4(10,Gt))("value",n.clustersToDisplay)("rows",10)("paginator",!0)("scrollable",!0))},dependencies:[h.bT,ee.XI,Dt.Ei,ee.hp,ee.c5,Mt.S,v.D9]})}return i})();function Zt(i,l){if(1&i&&(e.EFF(0,"\n "),e.j41(1,"span"),e.EFF(2," "),e.j41(3,"b"),e.EFF(4,"Name"),e.k0s(),e.EFF(5),e.j41(6,"b"),e.EFF(7,"NwkId"),e.k0s(),e.EFF(8),e.k0s(),e.EFF(9,"\n ")),2&i){const t=l.item;e.R7$(5),e.SpI(" : ",t.ZDeviceName," - "),e.R7$(3),e.SpI(" : ",t._NwkId,"")}}function Jt(i,l){if(1&i){const t=e.RV6();e.qex(0),e.EFF(1,"\n "),e.j41(2,"app-configure-cluster-reporting",16),e.bIt("clustersChange",function(n){e.eBV(t);const r=e.XpG();return e.Njj(r.onClustersChange(n))}),e.k0s(),e.EFF(3,"\n "),e.bVm()}if(2&i){const t=l.ngIf;e.R7$(2),e.Y8G("clusters",t)}}let Qt=(()=>{class i{toastr;apiService;translate;devices$;clusters$;deviceSelected;form;clustersToSave;permitToValidate=!1;constructor(t,o,n){this.toastr=t,this.apiService=o,this.translate=n}ngOnInit(){this.devices$=this.apiService.getZDevices()}getConfiguration(t){this.deviceSelected=null,t&&(this.deviceSelected=t._NwkId,this.clusters$=this.apiService.getConfigureReporting(this.deviceSelected))}putConfiguration(){this.apiService.putConfigureReporting(this.deviceSelected,this.clustersToSave).subscribe(()=>{this.permitToValidate=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}resetConfiguration(){this.apiService.deleteConfigureReporting(this.deviceSelected).subscribe(()=>{this.permitToValidate=!1,this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}triggerConfiguration(){this.apiService.getTriggerConfigureReporting(this.deviceSelected).subscribe(()=>{this.toastr.success(this.translate.instant("api.global.succes.saved.notify"))})}onClustersChange(t){this.permitToValidate=!1,this.clustersToSave=null,t&&(this.permitToValidate=!0,this.clustersToSave=t)}static \u0275fac=function(o){return new(o||i)(e.rXU(P.tw),e.rXU(A.G),e.rXU(v.c$))};static \u0275cmp=e.VBU({type:i,selectors:[["app-configure-reporting"]],decls:50,vars:30,consts:[[1,"col"],[1,"card"],[1,"card-header","d-flex"],[1,"col","fw-bold","justify-content-start"],[1,"col","d-flex","justify-content-end"],[1,"btn","btn-danger",3,"click","disabled","translate"],[1,"btn","btn-secondary","ms-3",3,"click","disabled","translate"],[1,"btn","btn-primary","ms-3",3,"click","disabled","translate"],[1,"card-body"],[1,"card-text",3,"innerHTML"],[1,"card-text"],[1,"row"],[1,"col-sm-3","mb-2"],["bindLabel","ZDeviceName","appendTo","body",3,"change","clear","items","multiple","closeOnSelect","searchable","placeholder"],["ng-option-tmp",""],[4,"ngIf"],[3,"clustersChange","clusters"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"div",1),e.EFF(3,"\n "),e.j41(4,"div",2),e.EFF(5,"\n "),e.j41(6,"div",3),e.EFF(7),e.nI1(8,"translate"),e.k0s(),e.EFF(9,"\n "),e.j41(10,"div",4),e.EFF(11,"\n "),e.j41(12,"button",5),e.nI1(13,"translate"),e.bIt("click",function(){return n.resetConfiguration()}),e.k0s(),e.EFF(14,"\n "),e.j41(15,"button",6),e.nI1(16,"translate"),e.bIt("click",function(){return n.triggerConfiguration()}),e.k0s(),e.EFF(17,"\n "),e.j41(18,"button",7),e.nI1(19,"translate"),e.bIt("click",function(){return n.putConfiguration()}),e.k0s(),e.EFF(20,"\n "),e.k0s(),e.EFF(21,"\n "),e.k0s(),e.EFF(22,"\n "),e.j41(23,"div",8),e.EFF(24,"\n "),e.nrm(25,"p",9),e.nI1(26,"translate"),e.EFF(27,"\n "),e.j41(28,"div",10),e.EFF(29,"\n "),e.j41(30,"div",11),e.EFF(31,"\n "),e.j41(32,"div",12),e.EFF(33,"\n "),e.j41(34,"ng-select",13),e.nI1(35,"translate"),e.nI1(36,"async"),e.bIt("change",function(s){return n.getConfiguration(s)})("clear",function(){return n.deviceSelected=null,n.permitToValidate=!1}),e.EFF(37,"\n "),e.DNE(38,Zt,10,2,"ng-template",14),e.EFF(39,"\n "),e.k0s(),e.EFF(40,"\n "),e.k0s(),e.EFF(41,"\n "),e.k0s(),e.EFF(42,"\n "),e.DNE(43,Jt,4,1,"ng-container",15),e.nI1(44,"async"),e.EFF(45,"\n "),e.k0s(),e.EFF(46,"\n "),e.k0s(),e.EFF(47,"\n "),e.k0s(),e.EFF(48,"\n"),e.k0s(),e.EFF(49,"\n")),2&o&&(e.R7$(7),e.JRh(e.bMT(8,14,"tools.reporting.configure.title")),e.R7$(5),e.FS9("translate",e.bMT(13,16,"tools.reporting.configure.reset.button")),e.Y8G("disabled",!n.deviceSelected),e.R7$(3),e.FS9("translate",e.bMT(16,18,"tools.reporting.configure.trigger.button")),e.Y8G("disabled",!n.deviceSelected),e.R7$(3),e.FS9("translate",e.bMT(19,20,"tools.reporting.configure.validate.button")),e.Y8G("disabled",!n.permitToValidate),e.R7$(7),e.Y8G("innerHTML",e.bMT(26,22,"tools.reporting.configure.subtitle"),e.npT),e.R7$(9),e.FS9("placeholder",e.bMT(35,24,"tools.reporting.configure.device")),e.Y8G("items",e.bMT(36,26,n.devices$))("multiple",!1)("closeOnSelect",!0)("searchable",!0),e.R7$(9),e.Y8G("ngIf",e.bMT(44,28,n.deviceSelected&&n.clusters$)))},dependencies:[h.bT,I.vr,I.Uq,v.Mm,Wt,h.Jj,v.D9]})}return i})(),$t=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275cmp=e.VBU({type:i,selectors:[["app-reporting"]],decls:5,vars:0,consts:[[1,"row","row-cols-1","g-4"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.nrm(2,"app-configure-reporting"),e.EFF(3,"\n"),e.k0s(),e.EFF(4,"\n"))},dependencies:[Qt]})}return i})();var en=m(27468);function tn(i,l){if(1&i){const t=e.RV6();e.j41(0,"button",15),e.bIt("click",function(){const n=e.eBV(t).ngIf,r=e.XpG();return e.Njj(r.download(n))}),e.k0s()}}function nn(i,l){if(1&i){const t=e.RV6();e.j41(0,"div",16),e.EFF(1,"\n "),e.j41(2,"button",17),e.bIt("click",function(){e.eBV(t);const n=e.XpG();return e.Njj(n.export(n.json))}),e.k0s(),e.EFF(3,"\n\n "),e.nrm(4,"ngx-json-viewer",18),e.EFF(5,"\n"),e.k0s()}if(2&i){const t=e.XpG();e.Y8G("hidden",t.isLoading),e.R7$(4),e.Y8G("expanded",!1)("json",t.json)}}let on=(()=>{class i{apiService;fileSaverService;json=null;isLoading=!1;logFile$;constructor(t,o){this.apiService=t,this.fileSaverService=o}ngOnInit(){this.logFile$=this.apiService.getLog()}onClick(t){let o;this.json=null,"devices"===t&&(o=this.apiService.getDevices()),"zdevices"===t&&(o=this.apiService.getZDevices()),"zgroups"===t&&(o=this.apiService.getZGroups()),"zdevice-raw"===t&&(o=this.apiService.getRawZDevices()),"infos"===t&&(o=this.apiService.getPlugin()),"coordinator"===t&&(o=this.apiService.getCoordinator()),"plugin-health"===t&&(o=this.apiService.getPluginhealth()),"zgroup-list-available-device"===t&&(o=this.apiService.getZGroupDevicesAvalaible()),"settings"===t&&(o=this.apiService.getSettings()),"plugin-stat"===t&&(o=this.apiService.getPluginStats()),"zdevice-name"===t&&(o=this.apiService.getZDeviceName()),"domoticz-env"===t&&(o=this.apiService.getDomoticzEnv()),"battery-state"===t&&(o=this.apiService.getBatteryState()),o&&o.pipe((0,ce.j)(()=>{this.isLoading=!1})).subscribe(n=>{this.callbackservice(n)})}getAllNonOptimizedDevice(){this.json=null,this.apiService.getZDeviceName().subscribe(t=>{const o=t.filter(n=>!n.CertifiedDevice).map(n=>this.getNonOptimizedDevice(n._NwkId));(0,en.p)(o).subscribe(n=>this.callbackservice(n))})}getNonOptimizedDevice(t){return this.apiService.getNonOptimizedDevice(t)}download(t){const o=t.Filename;this.apiService.downloadLog(t.URL).subscribe(n=>{this.fileSaverService.save(n.body,o)})}callbackservice(t){const o=JSON.stringify(t);this.json=JSON.parse(o,pe)}export(t){const o="export.json",n=this.fileSaverService.genType(o),r=new Blob([JSON.stringify(t)],{type:n});this.fileSaverService.save(r,o)}static \u0275fac=function(o){return new(o||i)(e.rXU(A.G),e.rXU(re))};static \u0275cmp=e.VBU({type:i,selectors:[["app-tools"]],decls:32,vars:4,consts:[[1,"row","d-flex","ms-2","gap-2"],["translate","tools.tools.zdevice-raw.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.non-optimized.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zgroup.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.plugin-stat.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.coordinator.infos.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["class","col-lg-2 col-md-4 col-sm-5 btn btn-primary","translate","tools.tools.log.button",3,"click",4,"ngIf"],["translate","tools.tools.infos.plugin.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.plugin-health.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.settings.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.domoticz-env.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.battery-state.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zdevice-name.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["translate","tools.tools.zgroup-list-available-device.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],["class","row ms-2 mt-2",3,"hidden",4,"ngIf"],["translate","tools.tools.log.button",1,"col-lg-2","col-md-4","col-sm-5","btn","btn-primary",3,"click"],[1,"row","ms-2","mt-2",3,"hidden"],["translate","tools.tools.export",1,"col-lg-1","mb-2","btn","btn-primary",3,"click"],[3,"expanded","json"]],template:function(o,n){1&o&&(e.j41(0,"div",0),e.EFF(1,"\n "),e.j41(2,"button",1),e.bIt("click",function(){return n.onClick("zdevice-raw")}),e.k0s(),e.EFF(3,"\n "),e.j41(4,"button",2),e.bIt("click",function(){return n.getAllNonOptimizedDevice()}),e.k0s(),e.EFF(5,"\n "),e.j41(6,"button",3),e.bIt("click",function(){return n.onClick("zgroups")}),e.k0s(),e.EFF(7,"\n "),e.j41(8,"button",4),e.bIt("click",function(){return n.onClick("plugin-stat")}),e.k0s(),e.EFF(9,"\n "),e.j41(10,"button",5),e.bIt("click",function(){return n.onClick("coordinator")}),e.k0s(),e.EFF(11,"\n "),e.DNE(12,tn,1,0,"button",6),e.nI1(13,"async"),e.EFF(14,"\n "),e.j41(15,"button",7),e.bIt("click",function(){return n.onClick("infos")}),e.k0s(),e.EFF(16,"\n "),e.j41(17,"button",8),e.bIt("click",function(){return n.onClick("plugin-health")}),e.k0s(),e.EFF(18,"\n "),e.j41(19,"button",9),e.bIt("click",function(){return n.onClick("settings")}),e.k0s(),e.EFF(20,"\n "),e.j41(21,"button",10),e.bIt("click",function(){return n.onClick("domoticz-env")}),e.k0s(),e.EFF(22,"\n "),e.j41(23,"button",11),e.bIt("click",function(){return n.onClick("battery-state")}),e.k0s(),e.EFF(24,"\n "),e.j41(25,"button",12),e.bIt("click",function(){return n.onClick("zdevice-name")}),e.k0s(),e.EFF(26,"\n "),e.j41(27,"button",13),e.bIt("click",function(){return n.onClick("zgroup-list-available-device")}),e.k0s(),e.EFF(28,"\n"),e.k0s(),e.EFF(29,"\n"),e.DNE(30,nn,6,3,"div",14),e.EFF(31,"\n")),2&o&&(e.R7$(12),e.Y8G("ngIf",e.bMT(13,2,n.logFile$)),e.R7$(18),e.Y8G("ngIf",n.json))},dependencies:[h.bT,v.Mm,se,h.Jj]})}return i})();const rn=[{path:"command",component:ut,data:{title:(0,V.o6)("command")}},{path:"debug",component:Rt,data:{title:(0,V.o6)("debug")}},{path:"binding",component:We,data:{title:(0,V.o6)("binding")}},{path:"link",component:on,data:{title:(0,V.o6)("tools")}},{path:"error",component:Vt,data:{title:(0,V.o6)("error")}},{path:"configure",component:$t,data:{title:(0,V.o6)("configure")}}];let sn=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({imports:[le.iI.forChild(rn),le.iI]})}return i})(),ln=(()=>{class i{static \u0275fac=function(o){return new(o||i)};static \u0275mod=e.$C({type:i});static \u0275inj=e.G2t({imports:[q.G,sn,qe,De,Ve]})}return i})()},2578:function(W,Y){var m,e;void 0!==(e="function"==typeof(m=function(){"use strict";function S(u,g,x){var f=new XMLHttpRequest;f.open("GET",u),f.responseType="blob",f.onload=function(){M(f.response,g,x)},f.onerror=function(){console.error("could not download file")},f.send()}function H(u){var g=new XMLHttpRequest;g.open("HEAD",u,!1);try{g.send()}catch{}return 200<=g.status&&299>=g.status}function D(u){try{u.dispatchEvent(new MouseEvent("click"))}catch{var g=document.createEvent("MouseEvents");g.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),u.dispatchEvent(g)}}var y="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,z=y.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),M=y.saveAs||("object"!=typeof window||window!==y?function(){}:"download"in HTMLAnchorElement.prototype&&!z?function(u,g,x){var f=y.URL||y.webkitURL,b=document.createElement("a");b.download=g=g||u.name||"download",b.rel="noopener","string"==typeof u?(b.href=u,b.origin===location.origin?D(b):H(b.href)?S(u,g,x):D(b,b.target="_blank")):(b.href=f.createObjectURL(u),setTimeout(function(){f.revokeObjectURL(b.href)},4e4),setTimeout(function(){D(b)},0))}:"msSaveOrOpenBlob"in navigator?function(u,g,x){if(g=g||u.name||"download","string"!=typeof u)navigator.msSaveOrOpenBlob(function h(u,g){return typeof g>"u"?g={autoBom:!1}:"object"!=typeof g&&(console.warn("Deprecated: Expected third argument to be a object"),g={autoBom:!g}),g.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(u.type)?new Blob(["\ufeff",u],{type:u.type}):u}(u,x),g);else if(H(u))S(u,g,x);else{var f=document.createElement("a");f.href=u,f.target="_blank",setTimeout(function(){D(f)})}}:function(u,g,x,f){if((f=f||open("","_blank"))&&(f.document.title=f.document.body.innerText="downloading..."),"string"==typeof u)return S(u,g,x);var b="application/octet-stream"===u.type,Z=/constructor/i.test(y.HTMLElement)||y.safari,U=/CriOS\/[\d]+/.test(navigator.userAgent);if((U||b&&Z||z)&&typeof FileReader<"u"){var G=new FileReader;G.onloadend=function(){var R=G.result;R=U?R:R.replace(/^data:[^;]*;/,"data:attachment/file;"),f?f.location.href=R:location=R,f=null},G.readAsDataURL(u)}else{var K=y.URL||y.webkitURL,N=K.createObjectURL(u);f?f.location=N:location.href=N,f=null,setTimeout(function(){K.revokeObjectURL(N)},4e4)}});y.saveAs=M.saveAs=M,W.exports=M})?m.apply(Y,[]):m)&&(W.exports=e)}}]); \ No newline at end of file diff --git a/www/z4d/index.html b/www/z4d/index.html index 1f1ef108d..b7e3c1790 100644 --- a/www/z4d/index.html +++ b/www/z4d/index.html @@ -24,5 +24,5 @@ This page requires JavaScript to work properly. Please enable JavaScript in your browser. -
This page requires JavaScript to work properly. Please enable JavaScript in your browser.