From bfcf67fe83cb1773ae83bf525c0685f5ad61ab8f Mon Sep 17 00:00:00 2001 From: trypton Date: Mon, 16 Mar 2026 09:04:42 +0100 Subject: [PATCH] **Version 1.3.2** - Hemos colocado un codigo de dos lineas para eliminar el boton del menu activo "COMPLETAR INFO" en caso que se presente una tarjeta o un codigo QR. Esto lo hicimos en el nodo "Analisis del modo de Operacion" en la linea 70 donde chequeamos si estamos en movimiento inicial. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Corregido un "error" que no permitia cerrar el movimiento inicial cuando se pasaba una tarjeta si teniamos el menu activo y la firma obligatoria. Se agrego una condicion ("ID_verificado") en la condicion global para llamar a la firma. Esto es en el nodo "Analisis de Operacion" en las primeras lineas if (flow.get("firma_obligatoria") && !flow.get("firma_flag") && !flow.get("firma_ok_flag") && !flow.get("supervisor") && (!flow.get("menu_activo") || (flow.get("menu_activo") && (flow.get("menu_seleccionado_flag") || ID_verificado)))) Con esto permite continuar con la firma en caso que tengamos menu_activo y firma obligatoria y entremos con tarjeta o con codigo QR. **Version 1.3.1** - Hemos colocado una opcion mas en el menu de configuración en "Pruebas del Sistema" -> "Probar Sensor". Esto permite visualizar la salida del valor de la distancia que esta midiendo el sensor cada segundo. Para que el medidor no este continuamente inundando el configurador con el dato de distancia hemos colocado un switch el cual solo deja pasar ese dato cuando se activa el menu, lo inhabilita cuando se sale del menu. - Hemos puesto el flag flow.set("RFID_ok_flag", false) cuando leemos un QR y flow.set("QR_ok_flag", false) cuando leemos una tarjeta, esto permite que se utilice un QR aunque primero hayamos metido una tarjeta invalida y viceversa. Se hizo en el nodo "envio QR/RFID". --- bascula_autonoma_1.json | 336 ++++++++++++++++++++------------- uibuilder/totem/src/index.css | 53 ++++++ uibuilder/totem/src/index.html | 30 +++ uibuilder/totem/src/index.js | 19 ++ 4 files changed, 311 insertions(+), 127 deletions(-) diff --git a/bascula_autonoma_1.json b/bascula_autonoma_1.json index 9a45d64..f007705 100644 --- a/bascula_autonoma_1.json +++ b/bascula_autonoma_1.json @@ -332,12 +332,15 @@ "de4c24109d3a3cec", "e82fc95572128625", "5eada7a4d497bdf2", - "1032df4341902ad3" + "1032df4341902ad3", + "8bfc0e03b763b6b1", + "eb6a49472973163d", + "41b4309de63a6bba" ], "x": 2534, "y": 1319, "w": 552, - "h": 1082 + "h": 1202 }, { "id": "2245c4484f098470", @@ -393,11 +396,13 @@ "6fca6204952f0b67", "3a321a461f6a4531", "f4c61087c128e20f", - "6d39924d1d2081dd" + "6d39924d1d2081dd", + "8ccf22739ca72997", + "7fd2f6e6fe3f37ea" ], "x": 3364, "y": 1999, - "w": 1022, + "w": 1162, "h": 482 }, { @@ -1931,7 +1936,7 @@ "z": "953e8740401d175c", "g": "595fb0f89af85c42", "name": "config comun", - "func": "var config = JSON.parse(msg.payload);\nmsg ={}; // clear msg object\nvar read;\n\nflow.set(\"vehiculo_activo_flag\", false);\nflow.set(\"last_QR\", \"\");\n\n//read = config.peso;\n//flow.set(\"peso\", read); // crea variable para recibir peso del supervisor\nread = config.peso_estable_flag;\nflow.set(\"peso_estable_flag\", read);\nread = config.peso_estable; // valor del peso estabilizado\nflow.set(\"peso_estable\", read);\nread = config.fin_pesada_flag;\nflow.set(\"fin_pesada_flag\", read);\nread = config.salida_vehiculo_flag;\nflow.set(\"salida_vehiculo_flag\", read);\nread = config.vehiculo_presente_flag;\nflow.set(\"vehiculo_presente_flag\", read);\nread = config.remover_firma;\nflow.set(\"remover_firma\", read);\n\nread = config.matricula_ok_flag;\nflow.set(\"matricula_ok_flag\", read);\nread = config.QR_ok_flag;\nflow.set(\"QR_ok_flag\", read);\nread = config.RFID\nflow.set(\"RFID\", read);\nread = config.RFID_ok_flag;\nflow.set(\"RFID_ok_flag\", read);\nread = config.QR_flag;\nflow.set(\"QR_flag\", read);\n\n\nread = config.auth_pin;\nflow.set(\"auth_pin\", read)\nread = config.pin_timeout; // timeout de espera del pin\nflow.set(\"pin_timeout\", read)\nread = config.mante_timeout; // timeout de la pantalla de mantenimiento\nflow.set(\"mante_timeout\", read)\n\nread = config.sw_bkgnd_on // color del background ON de los botones de seleccion de parametro \nflow.set(\"sw_bkgnd_on\", read);\nread = config.sw_bkgnd_off // color del background OFF de los botones de seleccion de parametro \nflow.set(\"sw_bkgnd_off\", read);\nread = config.titulo_param_color // color del nombre de los parametros\nflow.set(\"titulo_param_color\", read);\nflow.set(\"value_param_color\", read);\nread = config.namefixedparams_color // color del nombre de los parametros fijos (ip, serial, puertos remotos)\nflow.set(\"namefixedparams_color\", read);\nread = config.semaforo_green_color // color del semaforo en verde\nflow.set(\"semaforo_green_color\", read);\nread = config.semaforo_red_color // color del semaforo en rojo\nflow.set(\"semaforo_red_color\", read);\nread = config.titulo_matricula_color // color del titulo de la matricula y del ID\nflow.set(\"titulo_matricula_color\", read)\nread = config.valor_matricula_color // color del titulo de la matricula y del ID\nflow.set(\"valor_matricula_color\", read)\n\nread = config.totemid_max // maximo numero de identificacion asignado al totem\nflow.set(\"totemid_max\", read);\nread = config.vial_max // maximo numero de viales admitidos para asignar al dispositico\nflow.set(\"vial_max\", read);\n\n\n\n\nreturn", + "func": "var config = JSON.parse(msg.payload);\nmsg ={}; // clear msg object\nvar read;\n\nflow.set(\"vehiculo_activo_flag\", false);\nflow.set(\"last_QR\", \"-\");\n\n//read = config.peso;\n//flow.set(\"peso\", read); // crea variable para recibir peso del supervisor\nread = config.peso_estable_flag;\nflow.set(\"peso_estable_flag\", read);\nread = config.peso_estable; // valor del peso estabilizado\nflow.set(\"peso_estable\", read);\nread = config.fin_pesada_flag;\nflow.set(\"fin_pesada_flag\", read);\nread = config.salida_vehiculo_flag;\nflow.set(\"salida_vehiculo_flag\", read);\nread = config.vehiculo_presente_flag;\nflow.set(\"vehiculo_presente_flag\", read);\nread = config.remover_firma;\nflow.set(\"remover_firma\", read);\n\nread = config.matricula_ok_flag;\nflow.set(\"matricula_ok_flag\", read);\nread = config.QR_ok_flag;\nflow.set(\"QR_ok_flag\", read);\nread = config.RFID\nflow.set(\"RFID\", read);\nread = config.RFID_ok_flag;\nflow.set(\"RFID_ok_flag\", read);\nread = config.QR_flag;\nflow.set(\"QR_flag\", read);\n\n\nread = config.auth_pin;\nflow.set(\"auth_pin\", read)\nread = config.pin_timeout; // timeout de espera del pin\nflow.set(\"pin_timeout\", read)\nread = config.mante_timeout; // timeout de la pantalla de mantenimiento\nflow.set(\"mante_timeout\", read)\n\nread = config.sw_bkgnd_on // color del background ON de los botones de seleccion de parametro \nflow.set(\"sw_bkgnd_on\", read);\nread = config.sw_bkgnd_off // color del background OFF de los botones de seleccion de parametro \nflow.set(\"sw_bkgnd_off\", read);\nread = config.titulo_param_color // color del nombre de los parametros\nflow.set(\"titulo_param_color\", read);\nflow.set(\"value_param_color\", read);\nread = config.namefixedparams_color // color del nombre de los parametros fijos (ip, serial, puertos remotos)\nflow.set(\"namefixedparams_color\", read);\nread = config.semaforo_green_color // color del semaforo en verde\nflow.set(\"semaforo_green_color\", read);\nread = config.semaforo_red_color // color del semaforo en rojo\nflow.set(\"semaforo_red_color\", read);\nread = config.titulo_matricula_color // color del titulo de la matricula y del ID\nflow.set(\"titulo_matricula_color\", read)\nread = config.valor_matricula_color // color del titulo de la matricula y del ID\nflow.set(\"valor_matricula_color\", read)\n\nread = config.totemid_max // maximo numero de identificacion asignado al totem\nflow.set(\"totemid_max\", read);\nread = config.vial_max // maximo numero de viales admitidos para asignar al dispositico\nflow.set(\"vial_max\", read);\n\n\n\n\nreturn", "outputs": 1, "timeout": 0, "noerr": 0, @@ -2120,7 +2125,6 @@ "id": "0bc82cd2485c7679", "type": "inject", "z": "953e8740401d175c", - "d": true, "g": "6443f177eec330e4", "name": "distance ID1", "props": [ @@ -2226,7 +2230,9 @@ "g": "6443f177eec330e4", "name": "dist2ble", "mode": "link", - "links": [], + "links": [ + "7fd2f6e6fe3f37ea" + ], "x": 4315, "y": 1000, "wires": [] @@ -2279,7 +2285,9 @@ "x": 4120, "y": 1040, "wires": [ - [], + [ + "f730c0726e257f7f" + ], [ "20fe9f7863d4d4ec" ], @@ -3525,7 +3533,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Envio de mensajes", - "func": "// Este nodo realiza todos los envios de mensajes a los diferentes destinos: websocket, pantalla, relay\n\nif ((msg.id_topic == \"rfid\" || msg.id_topic == \"QR\") && flow.get(\"totem_master\")) { // si el mensaje proviene del lector de ID\n\n if (flow.get(\"RFID_ok_flag\") || flow.get(\"QR_ok_flag\")) {\n if(flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado)\")){\n flow.set(\"window_id_m4\", flow.get(\"id_leido\"));\n flow.set(\"window_men_m3\", \"\")\n }\n //flow.set(\"QR_ok_flag\", false)\n //flow.set(\"RFID_ok_flag\", false)\n if (flow.get(\"peso_bajo_flag\")) {\n // para el caso cuando queremos enviar tarjetas para asignar usuario en la base de datos\n //flow.set(\"window_id_m4\", flow.get(\"id_tarjeta\"));\n msg = {};\n setTimeout(function () {\n //node.warn(\"erase window\")\n //flow.set(\"QR_ok_flag\", false)\n //flow.set(\"RFID_ok_flag\", false)\n flow.set(\"window_id_m4\", \"\");\n // ================================== configura mensaje para las ventanas de la pantalla ===========================\n var msg_display = { \"id_m1\": \"\", \"id_m2\": \"\", \"id_m3\": \"\", \"id_m4\": \"\", \"men_m1\": \"\", \"men_m2\": \"\", \"men_m3\": \"\", \"peso\": \"\" };\n msg_display.id_m1 = flow.get(\"id_titulo_matricula\");\n msg_display.id_m2 = flow.get(\"matricula\");\n msg_display.id_m3 = flow.get(\"id_titulo_id\");\n msg_display.id_m4 = flow.get(\"window_id_m4\");\n\n msg_display.men_m1 = flow.get(\"window_men_m1\");\n msg_display.men_m2 = flow.get(\"window_men_m2\");\n msg_display.men_m3 = flow.get(\"window_men_m3\");\n\n msg_display.peso = flow.get(\"peso\");\n //asignamos el valor real del color del semaforo, este valor se define en el archivo de configuración\n if (flow.get(\"semaforo\") == \"green\") {\n msg_display.semaforo = flow.get(\"semaforo_green_color\")\n }\n else {\n msg_display.semaforo = flow.get(\"semaforo_red_color\")\n }\n\n\n // ==================================================================================================================\n node.send([msg_display, null, null, null])\n }, 3000)\n }\n\n\n }\n else {\n if (flow.get(\"vehiculo_presente_flag\")) {\n flow.set(\"window_id_m4\", flow.get(\"id_no_leido\"));\n }\n else {\n\n }\n\n\n }\n}\n//============================================== Chequea si Fin de Pesada y Saca Mensaje ===========================================\nif (flow.get(\"fin_pesada_flag\") && flow.get(\"totem_master\")) {\n setTimeout(() => {\n node.send([null, null, null, { payload: \"fin_pesada\" }]) // salida de audio de FIN DE PESADA <----\n }, 500);\n flow.set(\"fin_pesada_flag\", false) // evitamos que en esta pesada vuelva a entrar aqui nuevamente\n flow.set(\"semaforo\", \"green\")\n // sacar comando para barrera si esta se encuentra habilitada\n //node.send([null, { payload: 1 }, null, null])\n if (flow.get(\"barrera_habilitada\")) {\n node.send([null, { payload: 0 }, null, null])\n setTimeout(function () {\n node.send([null, { payload: 1 }, null, null])\n }, flow.get(\"relay2_pulse\"));\n }\n //flow.set(\"peso_estable_flag\", false)\n flow.set(\"botonsalida\", false)\n //coloca los mensajes para mostrar en pantalla \n flow.set(\"window_men_m1\", flow.get(\"men_pesaje_listo\"));\n flow.set(\"window_men_m2\", flow.get(\"men_salida\"));\n flow.set(\"window_men_m3\", \"\");\n}\n//===================================================================================================================== \n\n\n// ================================== configura mensaje para las ventanas de la pantalla ===========================\nvar msg_display = { \"id_m1\": \"\", \"id_m2\": \"\", \"id_m3\": \"\", \"id_m4\": \"\", \"men_m1\": \"\", \"men_m2\": \"\", \"men_m3\": \"\", \"peso\": \"\" };\nif (!flow.get(\"peso_bajo_flag\")) {\n msg_display.id_m2 = flow.get(\"matricula\");\n msg_display.id_m4 = flow.get(\"window_id_m4\");\n}\nelse{\n msg_display.id_m2 = \"\"\n msg_display.id_m4 = \"\"\n}\nmsg_display.id_m1 = flow.get(\"id_titulo_matricula\");\nmsg_display.id_m3 = flow.get(\"id_titulo_id\");\n\nmsg_display.men_m1 = flow.get(\"window_men_m1\");\nmsg_display.men_m2 = flow.get(\"window_men_m2\");\nmsg_display.men_m3 = flow.get(\"window_men_m3\");\n\nmsg_display.peso = flow.get(\"peso\");\n//asignamos el valor real del color del semaforo, este valor se define en el archivo de configuración\nmsg_display.semaforo = flow.get(\"semaforo\");\nif (flow.get(\"semaforo\") == \"green\") {\n msg_display.semaforo = flow.get(\"semaforo_green_color\")\n}\nelse {\n msg_display.semaforo = flow.get(\"semaforo_red_color\")\n}\nmsg_display.titulo_matricula_color = flow.get(\"titulo_matricula_color\") // color del texto del titulo de Matricula y del ID. Definido en el archivo de configuracion\nmsg_display.valor_matricula_color = flow.get(\"valor_matricula_color\") // color del texto del valor de la Matricula y del ID. Definido en el archivo de configuracion\nmsg_display.men_m1_color = \"#cc0000\" // color del mensaje de \"peso estable\" en la ventana W2\nmsg_display.men_m2_color = \"#6B3C01\" // color del mensaje de \"puede mover el vehiculo\" en la ventana W2\nmsg_display.men_m3_color = \"#386B01\" // color del mensaje de \"acerque tarjeta de ID\" en la ventana W2\n\n//============================Procesamiento botones en pantalla ======================================================\nif (flow.get(\"totem_master\")) {\n if (flow.get(\"startmenu_flag\")) { // check si tenemos que poner boton de solicitud de primer menu\n if (flow.get(\"button\") != undefined) {\n msg_display.button = flow.get(\"button\")\n }\n else {\n msg_display.button = \"button1\"\n }\n if (flow.get(\"button1\") != undefined) {\n msg_display.button1 = flow.get(\"button1\")\n }\n else {\n msg_display.button1 = \"COMPLETAR INFO.\"\n }\n if (flow.get(\"button2\") != undefined) {\n msg_display.button2 = flow.get(\"button2\")\n }\n else {\n msg_display.button2 = \"OK.\"\n }\n if (flow.get(\"men_linea1\") != undefined) {\n msg_display.men_m1 = flow.get(\"men_linea1\")\n }\n else {\n msg_display.men_m1 = \"Haga CLICK ABAJO\"\n }\n if (flow.get(\"men_linea2\") != undefined) {\n msg_display.men_m2 = flow.get(\"men_linea2\")\n }\n else {\n msg_display.men_m2 = \"\"\n }\n\n msg_display.men_m1_color = flow.get(\"men_linea1_color\")\n msg_display.men_m2_color = flow.get(\"men_linea2_color\")\n //flow.set(\"startmenu_flag\", false) // boton de solicitud de primer menu ejecutado\n // Este flag \"startmenu_flag\" debe ser puesto a false luego de haber sacado el menu o pasado la tarjeta\n // ya que si se pone a false antes de tocar el boton y viene otro valor de peso el boton desaparece de la pantalla\n }\n else {\n msg_display.button = \"message\"\n }\n // ==================================================================================================================\n\n //------------------------------ BOTON de VALIDACION ----------------------------------------------------------------\n if (flow.get(\"botonsalida\")) { // check si tenemos que poner boton de validacion a la salida. Si movimiento final siempre lo ponemos\n\n msg_display.button = \"button3\" // hace display de un boton de validacion\n\n // ------------ chequea si tenemos color del background del boton de validacion ---------------\n if (flow.get(\"botonsalida_color\") != undefined) {\n msg_display.botonvalidacion_background = flow.get(\"botonsalida_color\")\n }\n else {\n msg_display.botonvalidacion_background = flow.get(\"botonsalida_color_def\")\n }\n\n // ------------ chequea si tenemos color del texto del boton de validacion -----------------\n if (flow.get(\"botonsalida_txt_color\") != undefined) {\n msg_display.botonvalidacion_foreground = flow.get(\"botonsalida_txt_color\")\n }\n else {\n msg_display.botonvalidacion_foreground = flow.get(\"botonsalida_txt_color_def\")\n }\n\n // ------------ chequea si tenemos texto del boton de validacion -----------------\n if (flow.get(\"botonsalida_txt\") != undefined) {\n msg_display.button3 = flow.get(\"botonsalida_txt\")\n }\n else {\n msg_display.button3 = flow.get(\"botonsalida_txt_def\")\n }\n\n // ------------ chequea si tenemos texto del mensaje antes del boton de validacion ----------------- \n if (flow.get(\"botonsalida_mensaje1\") != undefined) {\n msg_display.men_m1 = flow.get(\"botonsalida_mensaje1\")\n }\n else {\n msg_display.men_m1 = flow.get(\"botonsalida_mensaje1_def\")\n }\n\n\n }\n\n}\n\n// ==================================================================================================================\nnode.send([msg_display, null, null, null])\n\n// ****************gestion del relay del semaforo****************\nif (flow.get(\"semaforo\") == \"green\") {\n node.send([null, null, { \"payload\": 1 }, null]);\n}\nelse {\n node.send([null, null, { \"payload\": 0 }, null]);\n}\n//*****************************************************************\n\nreturn;", + "func": "// Este nodo realiza todos los envios de mensajes a los diferentes destinos: websocket, pantalla, relay\n\nif ((msg.id_topic == \"rfid\" || msg.id_topic == \"QR\") && flow.get(\"totem_master\")) { // si el mensaje proviene del lector de ID\n\n if (flow.get(\"RFID_ok_flag\") || flow.get(\"QR_ok_flag\")) {\n if(flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado)\")){\n flow.set(\"window_id_m4\", flow.get(\"id_leido\"));\n flow.set(\"window_men_m3\", \"\")\n }\n //flow.set(\"QR_ok_flag\", false)\n //flow.set(\"RFID_ok_flag\", false)\n if (flow.get(\"peso_bajo_flag\")) {\n // para el caso cuando queremos enviar tarjetas para asignar usuario en la base de datos\n //flow.set(\"window_id_m4\", flow.get(\"id_tarjeta\"));\n msg = {};\n setTimeout(function () {\n //node.warn(\"erase window\")\n //flow.set(\"QR_ok_flag\", false)\n //flow.set(\"RFID_ok_flag\", false)\n flow.set(\"window_id_m4\", \"\");\n // ================================== configura mensaje para las ventanas de la pantalla ===========================\n var msg_display = { \"id_m1\": \"\", \"id_m2\": \"\", \"id_m3\": \"\", \"id_m4\": \"\", \"men_m1\": \"\", \"men_m2\": \"\", \"men_m3\": \"\", \"peso\": \"\" };\n msg_display.id_m1 = flow.get(\"id_titulo_matricula\");\n msg_display.id_m2 = flow.get(\"matricula\");\n msg_display.id_m3 = flow.get(\"id_titulo_id\");\n msg_display.id_m4 = flow.get(\"window_id_m4\");\n\n msg_display.men_m1 = flow.get(\"window_men_m1\");\n msg_display.men_m2 = flow.get(\"window_men_m2\");\n msg_display.men_m3 = flow.get(\"window_men_m3\");\n\n msg_display.peso = flow.get(\"peso\");\n //asignamos el valor real del color del semaforo, este valor se define en el archivo de configuración\n if (flow.get(\"semaforo\") == \"green\") {\n msg_display.semaforo = flow.get(\"semaforo_green_color\")\n }\n else {\n msg_display.semaforo = flow.get(\"semaforo_red_color\")\n }\n\n\n // ==================================================================================================================\n node.send([msg_display, null, null, null])\n }, 3000)\n }\n\n\n }\n else {\n if (flow.get(\"vehiculo_presente_flag\")) {\n flow.set(\"window_id_m4\", flow.get(\"id_no_leido\"));\n }\n else {\n\n }\n\n\n }\n}\n//============================================== Chequea si Fin de Pesada y Saca Mensaje ===========================================\nif (flow.get(\"fin_pesada_flag\") && flow.get(\"totem_master\")) {\n setTimeout(() => {\n node.send([null, null, null, { payload: \"fin_pesada\" }]) // salida de audio de FIN DE PESADA <----\n }, 500);\n flow.set(\"fin_pesada_flag\", false) // evitamos que en esta pesada vuelva a entrar aqui nuevamente\n flow.set(\"semaforo\", \"green\")\n // sacar comando para barrera si esta se encuentra habilitada\n //node.send([null, { payload: 1 }, null, null])\n if (flow.get(\"barrera_habilitada\")) {\n node.send([null, { payload: 0 }, null, null])\n setTimeout(function () {\n node.send([null, { payload: 1 }, null, null])\n }, flow.get(\"relay2_pulse\"));\n }\n //flow.set(\"peso_estable_flag\", false)\n flow.set(\"botonsalida\", false)\n //coloca los mensajes para mostrar en pantalla \n flow.set(\"window_men_m1\", flow.get(\"men_pesaje_listo\"));\n flow.set(\"window_men_m2\", flow.get(\"men_salida\"));\n flow.set(\"window_men_m3\", \"\");\n}\n//===================================================================================================================== \n\n\n// ================================== configura mensaje para las ventanas de la pantalla ===========================\nvar msg_display = { \"id_m1\": \"\", \"id_m2\": \"\", \"id_m3\": \"\", \"id_m4\": \"\", \"men_m1\": \"\", \"men_m2\": \"\", \"men_m3\": \"\", \"peso\": \"\" };\nif (!flow.get(\"peso_bajo_flag\")) {\n msg_display.id_m2 = flow.get(\"matricula\");\n msg_display.id_m4 = flow.get(\"window_id_m4\");\n}\nelse{\n msg_display.id_m2 = \"\"\n msg_display.id_m4 = \"\"\n}\nmsg_display.id_m1 = flow.get(\"id_titulo_matricula\");\nmsg_display.id_m3 = flow.get(\"id_titulo_id\");\n\nmsg_display.men_m1 = flow.get(\"window_men_m1\");\nmsg_display.men_m2 = flow.get(\"window_men_m2\");\nmsg_display.men_m3 = flow.get(\"window_men_m3\");\n\nmsg_display.peso = flow.get(\"peso\");\n//asignamos el valor real del color del semaforo, este valor se define en el archivo de configuración\nmsg_display.semaforo = flow.get(\"semaforo\");\nif (flow.get(\"semaforo\") == \"green\") {\n msg_display.semaforo = flow.get(\"semaforo_green_color\")\n}\nelse {\n msg_display.semaforo = flow.get(\"semaforo_red_color\")\n}\nmsg_display.titulo_matricula_color = flow.get(\"titulo_matricula_color\") // color del texto del titulo de Matricula y del ID. Definido en el archivo de configuracion\nmsg_display.valor_matricula_color = flow.get(\"valor_matricula_color\") // color del texto del valor de la Matricula y del ID. Definido en el archivo de configuracion\nmsg_display.men_m1_color = \"#cc0000\" // color del mensaje de \"peso estable\" en la ventana W2\nmsg_display.men_m2_color = \"#6B3C01\" // color del mensaje de \"puede mover el vehiculo\" en la ventana W2\nmsg_display.men_m3_color = \"#386B01\" // color del mensaje de \"acerque tarjeta de ID\" en la ventana W2\n\n//============================Procesamiento botones en pantalla ======================================================\nif (flow.get(\"totem_master\")) {\n if (flow.get(\"startmenu_flag\")) { // check si tenemos que poner boton de solicitud de primer menu\n if (flow.get(\"button\") != undefined) {\n msg_display.button = flow.get(\"button\")\n }\n else {\n msg_display.button = \"button1\"\n }\n if (flow.get(\"button1\") != undefined) {\n msg_display.button1 = flow.get(\"button1\")\n }\n else {\n msg_display.button1 = \"COMPLETAR INFO.\"\n }\n if (flow.get(\"button2\") != undefined) {\n msg_display.button2 = flow.get(\"button2\")\n }\n else {\n msg_display.button2 = \"OK.\"\n }\n if (flow.get(\"men_linea1\") != undefined) {\n msg_display.men_m1 = flow.get(\"men_linea1\")\n }\n else {\n msg_display.men_m1 = \"Haga CLICK ABAJO\"\n }\n if (flow.get(\"men_linea2\") != undefined) {\n msg_display.men_m2 = flow.get(\"men_linea2\")\n }\n else {\n msg_display.men_m2 = \"\"\n }\n\n msg_display.men_m1_color = flow.get(\"men_linea1_color\")\n msg_display.men_m2_color = flow.get(\"men_linea2_color\")\n //flow.set(\"startmenu_flag\", false) // boton de solicitud de primer menu ejecutado\n // Este flag \"startmenu_flag\" debe ser puesto a false luego de haber sacado el menu o pasado la tarjeta\n // ya que si se pone a false antes de tocar el boton y viene otro valor de peso el boton desaparece de la pantalla\n }\n else {\n msg_display.button = \"message\" // indica que no pone boton sino que escribe mensajes \n }\n // ==================================================================================================================\n\n //------------------------------ BOTON de VALIDACION ----------------------------------------------------------------\n if (flow.get(\"botonsalida\")) { // check si tenemos que poner boton de validacion a la salida. Si movimiento final siempre lo ponemos\n\n msg_display.button = \"button3\" // hace display de un boton de validacion\n\n // ------------ chequea si tenemos color del background del boton de validacion ---------------\n if (flow.get(\"botonsalida_color\") != undefined) {\n msg_display.botonvalidacion_background = flow.get(\"botonsalida_color\")\n }\n else {\n msg_display.botonvalidacion_background = flow.get(\"botonsalida_color_def\")\n }\n\n // ------------ chequea si tenemos color del texto del boton de validacion -----------------\n if (flow.get(\"botonsalida_txt_color\") != undefined) {\n msg_display.botonvalidacion_foreground = flow.get(\"botonsalida_txt_color\")\n }\n else {\n msg_display.botonvalidacion_foreground = flow.get(\"botonsalida_txt_color_def\")\n }\n\n // ------------ chequea si tenemos texto del boton de validacion -----------------\n if (flow.get(\"botonsalida_txt\") != undefined) {\n msg_display.button3 = flow.get(\"botonsalida_txt\")\n }\n else {\n msg_display.button3 = flow.get(\"botonsalida_txt_def\")\n }\n\n // ------------ chequea si tenemos texto del mensaje antes del boton de validacion ----------------- \n if (flow.get(\"botonsalida_mensaje1\") != undefined) {\n msg_display.men_m1 = flow.get(\"botonsalida_mensaje1\")\n }\n else {\n msg_display.men_m1 = flow.get(\"botonsalida_mensaje1_def\")\n }\n\n\n }\n\n}\n\n// ==================================================================================================================\nnode.send([msg_display, null, null, null])\n\n// ****************gestion del relay del semaforo****************\nif (flow.get(\"semaforo\") == \"green\") {\n node.send([null, null, { \"payload\": 1 }, null]);\n}\nelse {\n node.send([null, null, { \"payload\": 0 }, null]);\n}\n//*****************************************************************\n\nreturn;", "outputs": 4, "timeout": "", "noerr": 0, @@ -3899,7 +3907,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Peso", - "func": "let peso = flow.get(\"peso\") || 0;\nconst peso_minimo = flow.get(\"peso_minimo\");\nlet peso_estable = flow.get(\"peso_estable\");\nlet semaforo = flow.get(\"semaforo\");\n\nif (peso < peso_minimo) {\n // evento de bascula OFF para cuando el totem no dispone de sensor remoto\n /* eliminamos este trigger para el evento de la bascula\n if (peso < (peso_minimo * 0.8) && flow.get(\"peso_trigger_ON\")) {// consideramos una histeresis\n flow.set(\"peso_trigger_ON\", false) // marcamos que el trigger ON esta en FALSE para proxima activacion de la bascula\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, null])\n }\n */\n //===========================================================================\n if(!flow.get(\"peso_bajo_flag\")){ // Se cumple solo una vez al vaciar la bascula\n \n flow.set(\"matricula_image\", \"\") // inicializamos imagen del vehiculo\n flow.set(\"plate_sent\", false)\n flow.set(\"anpr1_flag\", false)\n flow.set(\"anpr0_flag\", true)\n \n // Esto corresponde al nodo \"espera\" puesto ahi para el caso en que la imagen llegue antes que el evento de bascula en el caso de dos totems\n flow.set(\"interval_matricula\", null);\n flow.set(\"interval_running\", false);\n flow.set(\"order_sent\", false);\n flow.set(\"peso_bajo_flag_forzado\", false) // indica que se ha forzado el estado del peso de la bascula para poder resetear las variables\n //----------------------------------------------------------------------------------------------------------------------------\n flow.set(\"matricula_revisada\", false)\n flow.set(\"matricula_autorizada\", false)\n flow.set(\"last_firma\", \"\") // inicializamos imagen de la firma\n flow.set(\"identificacion_pendiente\", false) // estas cuatro lineas son relativas a la identificacion especial para cuando no se puede leer la matricula\n flow.set(\"identificacion_esp_aplicada\", false) // indica que la matricula no fue bien leida y se aplico el parametro de identificacion especial\n flow.set(\"QR_revisado\", false)\n flow.set(\"RFID_revisado\", false)\n flow.set(\"QR_verificado\", false)\n flow.set(\"RFID_verificado\", false)\n flow.set(\"peso_bajo_flag\", true)\n flow.set(\"matricula_leida_flag\", false)\n flow.set(\"matricula_formato_flag\", false)\n flow.set(\"snapshot_rq_flag\", false)\n flow.set(\"lista_array\", [])\n flow.set(\"menu0\", [])\n flow.set(\"menu1\", [])\n flow.set(\"menu2\", [])\n flow.set(\"menu_seleccionado_flag\", false)// indicador de que el usuario termino la seleccion en el menu y se envio\n flow.set(\"id_seleccionado\", \"no recibido\")\n flow.set(\"mostrar_ubicacion_ok\", false)\n flow.set(\"ubicacion_recibida\", false)\n flow.set(\"ubicacion_interna\", false)\n flow.set(\"startmenu_flag\", false) // reset del flag que permite mostrar el boton (\"completar informacion\") de acceso al menu de materiales\n flow.set(\"editor_matricula_ok\", false) // se activa cuando el usuario hace clik en OK para ir a editar la matricula\n flow.set(\"badplate_llamado\", false) // se activa cuando se saca por primera vez la notificacion para EDITRA MATRICULA en la siguiente pantalla\n flow.set(\"nota_modifique_matricula_done\", false) // nota al usuario cuando hay que modificar matricula no registrada\n flow.set(\"nota_vuelva_intentar_done\", false) // nota al usuario despues de corregir la matricula en caso de error\n flow.set(\"nota_avise_basculista_done\", false) // nota al usuario de aviso al basculista\n flow.set(\"nota_resumen_mostrada\", false) // indica que la nota de resumen luego de presentar identificacion ya se mostro (nodo QR / RFID)\n flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n flow.set(\"badplate\", false)\n flow.set(\"distance_flag_SET\", false)\n flow.set(\"semaforoabierto\", true) // flag para gestion del semaforo desde websocket\n //Atributos del vehiculo, leidos de la BD al momento de revisar si la matricula existe en BD\n flow.set(\"pma\", 0)\n flow.set(\"tara\", 0)\n flow.set(\"tipo_movimiento\", \"nodefinido\")\n flow.set(\"register\", {})\n flow.set(\"movimiento_enviado\", false)\n flow.set(\"matriculacheck_solicitada\", false) // flag utilizado para no repetir el envio de la revision de matricula en el nodo Matricula\n \n if (flow.get(\"switch_2_Totem_page\")) { //En caso que este flag haya sido habilitado en configuracion \n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta y cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n \n node.send([null, null, null, null, null, { payload: \"\" }, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n else {\n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta\n node.send([null, null, null, null, null, { payload: \"\" }, null, null]);\n }\n }\n //==========================================================================================================================\n flow.set(\"peso_estable_flag\", false)\n flow.set(\"peso_estable_audio_flag\", true)\n flow.set(\"peso_estable\", 0)\n flow.set(\"fin_pesada_flag\", false)\n //flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n if (flow.get(\"totem_qty\") == 1) { flow.set(\"totem_master\", true) } // en el caso de un solo totem. Este dispositivo siempre sera el master\n //flow.set(\"firma_activa\", false)\n flow.set(\"QR_ok_flag\", false);\n flow.set(\"RFID_ok_flag\", false);\n flow.set(\"last_QR\", \"-\")\n flow.set(\"last_RFID\", \"-\")\n flow.set(\"botonsalida\", false)\n flow.set(\"vehiculo_en_posicion\", false)\n flow.set(\"salida_valida_flag\", false)\n \n flow.set(\"aviso_pma_hecho\", false) // reset del flag indicador de PMA\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"matricula_editada_flag\", false)\n //flow.set(\"matricula\", \"Sin Matricula\")\n //flow.set(\"snapshot_rq_flag\", false)\n //flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n //flow.set(\"badplate\", false)\n flow.set(\"firma_ok_flag\", false) // firma recibida\n flow.set(\"firma_flag\", false) // solicitud de firma\n flow.set(\"movimiento_registrado_flag\", false)\n if (flow.get((\"semaforoabierto\"))){ // si el semaforo ha sido manipulado desde websocket entonces no lo tocamos\n flow.set(\"semaforo\", \"green\")\n }\n flow.set(\"window_men_m1\", \"\"); // borra posibles mensajes en pantalla \n flow.set(\"window_men_m2\", \"\"); \n flow.set(\"window_men_m3\", \"\");\n flow.set(\"window_id_m4\", \"\");\n flow.set(\"window_id_m2\", \"\");\n \n \n}\nelse {// ************************ peso > pmin *****************************************\n if (flow.get(\"peso_bajo_flag\")) {\n flow.set(\"peso_min_time\", new Date().getTime()) // marca momento en que se detecta peso > peso min\n //node.warn(\"peso_min_time = \" + flow.get(\"peso_min_time\"))\n flow.set(\"horaentrada\", new Date(flow.get(\"peso_min_time\")).toLocaleString()) // Convierte a formato legible\n // evento de bascula ON para cuando hay un solo Totem en la bascula (sin sensor remoto)\n /*\n if (flow.get(\"peso_trigger_ON\") == false) {\n flow.set(\"peso_trigger_ON\", true) // \n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null])\n }\n */\n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null]) // sacamos evento de bascula ON cuando no hay sensor remoto\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"badplate\", false) // inicializamos flag en caso que haya sido enviado cuando peso < pmin \n flow.set(\"vehiculo_presente_flag\", true);\n flow.set(\"ID_enviado\", false) // activamos flag para envio de un unico RFID / QR con peso > pmin\n flow.set(\"esperando_id\", true)\n flow.set(\"peso_bajo_flag\", false);\n\n flow.set(\"semaforo\", \"red\")\n node.send([{ payload: 1 }, null, null, null, null, null, null, null]) // generamos un nuevo UUID\n setTimeout(function () {\n let new_register = {\n uuid: flow.get(\"new_uuid\"),\n horaentrada: flow.get(\"horaentrada\"),\n vial: flow.get(\"numero_vial\"),\n totem: flow.get(\"totem_id\"),\n sincro: false,\n modo: flow.get(\"modo_totem\"),\n firmaobligatoria: flow.get(\"firma_obligatoria\"),\n id_seleccionado: \"no recibido\",\n nombre_firma: \"No Habilitada\",\n QR: \"-\",\n RFID: \"-\",\n matricula: \"Sin Matricula\",\n nombre_imagen: \"Sin Matricula\",\n sentido: \"No conocido\"\n }\n flow.set(\"register\", new_register)\n }, 1000)\n\n if (flow.get(\"switch_2_Totem_page\")) { // si ha sido habilitado cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n node.send([null, null, null, null, null, null, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n \n if ((flow.get(\"modo_totem\") == \"C\" || flow.get(\"modo_totem\") == \"D\" ) && !flow.get(\"supervisor\")){\n if(flow.get(\"botonsalida_activo\")){\n flow.set(\"botonsalida\", true)\n }\n }\n }\n if (flow.get(\"peso_estable_flag\")) {\n flow.set(\"peso\", flow.get(\"peso_estable\"));\n } \n\n \n //-------------------------------procesamiento de la lista de materiales-----------------------------------------------------\n //if (flow.get(\"lista_flag\") && flow.get(\"supervisor\")) {\n if (flow.get(\"lista_flag\")) {\n flow.set(\"lista_flag\", false) // evita otra entrada a esta secuencia para esta misma lista\n var lista = flow.get(\"lista_array\") // lista con todos los materiales y niveles juntos\n const lista_size = flow.get(\"lista_array\").length\n let j = 0; let k = 0; let i = 0; let maxlevel = 0;\n for (i = 0; i < lista_size; i++) { // calculamos el nivel maximo que tiene esta lista de menu\n if (parseInt(lista[i].nivel) > maxlevel) {\n maxlevel = parseInt(lista[i].nivel)\n }\n }\n flow.set(\"maxlevel\", maxlevel + 1) // guardamos el maximo nivel de menu identificado en la lista\n flow.set(\"selections\", \"\") //inicializamos con ninguna seleccion\n if (flow.get(\"menu_inicio\")) {\n flow.set(\"startmenu_flag\", true)\n }\n\n }\n\n //----------------------------------- FIN Lista de Materiales -----------------------------------------------------------------------\n}\n\nreturn ([null, null, null, null, msg, null, null, null]);\n", + "func": "let peso = flow.get(\"peso\") || 0;\nconst peso_minimo = flow.get(\"peso_minimo\");\nlet peso_estable = flow.get(\"peso_estable\");\nlet semaforo = flow.get(\"semaforo\");\n\nif (peso < peso_minimo) {\n // evento de bascula OFF para cuando el totem no dispone de sensor remoto\n /* eliminamos este trigger para el evento de la bascula\n if (peso < (peso_minimo * 0.8) && flow.get(\"peso_trigger_ON\")) {// consideramos una histeresis\n flow.set(\"peso_trigger_ON\", false) // marcamos que el trigger ON esta en FALSE para proxima activacion de la bascula\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, null])\n }\n */\n //===========================================================================\n if(!flow.get(\"peso_bajo_flag\")){ // Se cumple solo una vez al vaciar la bascula\n \n flow.set(\"matricula_image\", \"\") // inicializamos imagen del vehiculo\n flow.set(\"plate_sent\", false)\n flow.set(\"anpr1_flag\", false)\n flow.set(\"anpr0_flag\", true)\n \n // Esto corresponde al nodo \"espera\" puesto ahi para el caso en que la imagen llegue antes que el evento de bascula en el caso de dos totems\n flow.set(\"interval_matricula\", null);\n flow.set(\"interval_running\", false);\n flow.set(\"order_sent\", false);\n flow.set(\"peso_bajo_flag_forzado\", false) // indica que se ha forzado el estado del peso de la bascula para poder resetear las variables\n //----------------------------------------------------------------------------------------------------------------------------\n flow.set(\"matricula_revisada\", false)\n flow.set(\"matricula_autorizada\", false)\n flow.set(\"last_firma\", \"\") // inicializamos imagen de la firma\n flow.set(\"identificacion_pendiente\", false) // estas cuatro lineas son relativas a la identificacion especial para cuando no se puede leer la matricula\n flow.set(\"identificacion_esp_aplicada\", false) // indica que la matricula no fue bien leida y se aplico el parametro de identificacion especial\n flow.set(\"QR_revisado\", false)\n flow.set(\"RFID_revisado\", false)\n flow.set(\"QR_verificado\", false)\n flow.set(\"RFID_verificado\", false)\n flow.set(\"peso_bajo_flag\", true)\n flow.set(\"matricula_leida_flag\", false)\n flow.set(\"matricula_formato_flag\", false)\n flow.set(\"snapshot_rq_flag\", false)\n flow.set(\"lista_array\", [])\n flow.set(\"menu0\", [])\n flow.set(\"menu1\", [])\n flow.set(\"menu2\", [])\n flow.set(\"menu_seleccionado_flag\", false)// indicador de que el usuario termino la seleccion en el menu y se envio\n flow.set(\"id_seleccionado\", \"no recibido\")\n flow.set(\"mostrar_ubicacion_ok\", false)\n flow.set(\"ubicacion_recibida\", false)\n flow.set(\"ubicacion_interna\", false)\n flow.set(\"startmenu_flag\", false) // reset del flag que permite mostrar el boton (\"completar informacion\") de acceso al menu de materiales\n flow.set(\"editor_matricula_ok\", false) // se activa cuando el usuario hace clik en OK para ir a editar la matricula\n flow.set(\"badplate_llamado\", false) // se activa cuando se saca por primera vez la notificacion para EDITRA MATRICULA en la siguiente pantalla\n flow.set(\"nota_modifique_matricula_done\", false) // nota al usuario cuando hay que modificar matricula no registrada\n flow.set(\"nota_vuelva_intentar_done\", false) // nota al usuario despues de corregir la matricula en caso de error\n flow.set(\"nota_avise_basculista_done\", false) // nota al usuario de aviso al basculista\n flow.set(\"nota_resumen_mostrada\", false) // indica que la nota de resumen luego de presentar identificacion ya se mostro (nodo QR / RFID)\n flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n flow.set(\"badplate\", false)\n flow.set(\"distance_flag_SET\", false)\n flow.set(\"semaforoabierto\", true) // flag para gestion del semaforo desde websocket\n //Atributos del vehiculo, leidos de la BD al momento de revisar si la matricula existe en BD\n flow.set(\"pma\", 0)\n flow.set(\"tara\", 0)\n flow.set(\"tipo_movimiento\", \"nodefinido\")\n flow.set(\"register\", {})\n flow.set(\"movimiento_enviado\", false)\n flow.set(\"matriculacheck_solicitada\", false) // flag utilizado para no repetir el envio de la revision de matricula en el nodo Matricula\n flow.set(\"display_detector\", false) // flag que permite ver el valor del detector de objetos en la pantalla de configuracion. Se pone en true al entrar en el menus de Probar Sensor\n \n if (flow.get(\"switch_2_Totem_page\")) { //En caso que este flag haya sido habilitado en configuracion \n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta y cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n \n node.send([null, null, null, null, null, { payload: \"\" }, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n else {\n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta\n node.send([null, null, null, null, null, { payload: \"\" }, null, null]);\n }\n }\n //==========================================================================================================================\n flow.set(\"peso_estable_flag\", false)\n flow.set(\"peso_estable_audio_flag\", true)\n flow.set(\"peso_estable\", 0)\n flow.set(\"fin_pesada_flag\", false)\n //flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n if (flow.get(\"totem_qty\") == 1) { flow.set(\"totem_master\", true) } // en el caso de un solo totem. Este dispositivo siempre sera el master\n //flow.set(\"firma_activa\", false)\n flow.set(\"QR_ok_flag\", false);\n flow.set(\"RFID_ok_flag\", false);\n flow.set(\"last_QR\", \"-\")\n flow.set(\"last_RFID\", \"-\")\n flow.set(\"botonsalida\", false)\n flow.set(\"vehiculo_en_posicion\", false)\n flow.set(\"salida_valida_flag\", false)\n \n flow.set(\"aviso_pma_hecho\", false) // reset del flag indicador de PMA\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"matricula_editada_flag\", false)\n //flow.set(\"matricula\", \"Sin Matricula\")\n //flow.set(\"snapshot_rq_flag\", false)\n //flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n //flow.set(\"badplate\", false)\n flow.set(\"firma_ok_flag\", false) // firma recibida\n flow.set(\"firma_flag\", false) // solicitud de firma\n flow.set(\"movimiento_registrado_flag\", false)\n if (flow.get((\"semaforoabierto\"))){ // si el semaforo ha sido manipulado desde websocket entonces no lo tocamos\n flow.set(\"semaforo\", \"green\")\n }\n flow.set(\"window_men_m1\", \"\"); // borra posibles mensajes en pantalla \n flow.set(\"window_men_m2\", \"\"); \n flow.set(\"window_men_m3\", \"\");\n flow.set(\"window_id_m4\", \"\");\n flow.set(\"window_id_m2\", \"\");\n \n \n}\nelse {// ************************ peso > pmin *****************************************\n if (flow.get(\"peso_bajo_flag\")) {\n flow.set(\"peso_min_time\", new Date().getTime()) // marca momento en que se detecta peso > peso min\n //node.warn(\"peso_min_time = \" + flow.get(\"peso_min_time\"))\n flow.set(\"horaentrada\", new Date(flow.get(\"peso_min_time\")).toLocaleString()) // Convierte a formato legible\n // evento de bascula ON para cuando hay un solo Totem en la bascula (sin sensor remoto)\n /*\n if (flow.get(\"peso_trigger_ON\") == false) {\n flow.set(\"peso_trigger_ON\", true) // \n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null])\n }\n */\n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null]) // sacamos evento de bascula ON cuando no hay sensor remoto\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"badplate\", false) // inicializamos flag en caso que haya sido enviado cuando peso < pmin \n flow.set(\"vehiculo_presente_flag\", true);\n flow.set(\"ID_enviado\", false) // activamos flag para envio de un unico RFID / QR con peso > pmin\n flow.set(\"esperando_id\", true)\n flow.set(\"peso_bajo_flag\", false);\n\n flow.set(\"semaforo\", \"red\")\n node.send([{ payload: 1 }, null, null, null, null, null, null, null]) // generamos un nuevo UUID\n setTimeout(function () {\n let new_register = {\n uuid: flow.get(\"new_uuid\"),\n horaentrada: flow.get(\"horaentrada\"),\n vial: flow.get(\"numero_vial\"),\n totem: flow.get(\"totem_id\"),\n sincro: false,\n modo: flow.get(\"modo_totem\"),\n firmaobligatoria: flow.get(\"firma_obligatoria\"),\n id_seleccionado: \"no recibido\",\n nombre_firma: \"No Habilitada\",\n qr: \"-\",\n rfid: \"-\",\n matricula: \"Sin Matricula\",\n nombre_imagen: \"Sin Matricula\",\n sentido: \"No conocido\"\n }\n flow.set(\"register\", new_register)\n }, 1000)\n\n if (flow.get(\"switch_2_Totem_page\")) { // si ha sido habilitado cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n node.send([null, null, null, null, null, null, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n \n if ((flow.get(\"modo_totem\") == \"C\" || flow.get(\"modo_totem\") == \"D\" ) && !flow.get(\"supervisor\")){\n if(flow.get(\"botonsalida_activo\")){\n flow.set(\"botonsalida\", true)\n }\n }\n }\n if (flow.get(\"peso_estable_flag\")) {\n flow.set(\"peso\", flow.get(\"peso_estable\"));\n } \n\n \n //-------------------------------procesamiento de la lista de materiales-----------------------------------------------------\n //if (flow.get(\"lista_flag\") && flow.get(\"supervisor\")) {\n if (flow.get(\"lista_flag\")) {\n flow.set(\"lista_flag\", false) // evita otra entrada a esta secuencia para esta misma lista\n var lista = flow.get(\"lista_array\") // lista con todos los materiales y niveles juntos\n const lista_size = flow.get(\"lista_array\").length\n let j = 0; let k = 0; let i = 0; let maxlevel = 0;\n for (i = 0; i < lista_size; i++) { // calculamos el nivel maximo que tiene esta lista de menu\n if (parseInt(lista[i].nivel) > maxlevel) {\n maxlevel = parseInt(lista[i].nivel)\n }\n }\n flow.set(\"maxlevel\", maxlevel + 1) // guardamos el maximo nivel de menu identificado en la lista\n flow.set(\"selections\", \"\") //inicializamos con ninguna seleccion\n if (flow.get(\"menu_inicio\")) {\n flow.set(\"startmenu_flag\", true)\n }\n\n }\n\n //----------------------------------- FIN Lista de Materiales -----------------------------------------------------------------------\n}\n\nreturn ([null, null, null, null, msg, null, null, null]);\n", "outputs": 7, "timeout": 0, "noerr": 0, @@ -3940,7 +3948,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Analisis del modo \\n de Operacion", - "func": "//***************************** Selecciona Modo de Operacion **************************************************\nif (!flow.get(\"supervisor\")) {\n if (flow.get(\"peso_estable_flag\")) { //El peso estable se obtiene cuando el vehiculo esta frente al Totem (QR / RFID o sino Detector Local ON o bien pulsar un boton que aparezca en pantalla)\n if (flow.get(\"tipo_movimiento\") == \"final\") {\n flow.set(\"firma_ok_flag\", true) // indicamos que la firma esta hecha, esta no hace falta para la salida\n }\n if (flow.get(\"firma_obligatoria\") && !flow.get(\"firma_flag\") &&!flow.get(\"firma_ok_flag\") && !flow.get(\"supervisor\") && (!flow.get(\"menu_activo\") || (flow.get(\"menu_activo\") && flow.get(\"menu_seleccionado_flag\")))) { //chequea si tenemos que solicitar firma\n /*\n El if anterior se cumple si:\n - firma_obligatoria es true y firma_ok_flag es false y firma_flag es false y si supervisor es false y ademas si menu_activo es false o bien menu_activo es true y menu_seleccionado_flag es true (osea se ha seleccionado el menu)\n Con esto aseguramos que la firma la sacamos una vez que el usuario ha hecho la seleccion del menu (en caso de existir) y no antes.\n */\n // hemos cambiado \"firma_habilitada\" por \"firma_obligatoria\" porque finalmente con un solo parametro es suficiente\n // finalmente hacemos el llamado a la firma solamente durante el movimiento inicial\n if (flow.get(\"tipo_movimiento\") == \"inicial\") {\n flow.set(\"firma_flag\", true) // solicitud de firma\n setTimeout(() => {\n node.warn(\"solicitando firma\")\n node.send([{ \"payload\": { \"tab\": \"Firma\" } }, { payload: \"firma\" }, null, null])\n }, 500);\n }\n /*\n else if (flow.get(\"tipo_movimiento\") == \"final\") {\n flow.set(\"firma_ok_flag\", true) // indicamos que la firma esta hecha, esta no hace falta para la salida\n }\n */\n }\n\n //=============================================================================================================================================\n //====================================================== MODO DE OPERACION ====================================================================\n //=============================================================================================================================================\n let modo = flow.get(\"modo_totem\")\n // -----------------------------------------------------COMUN PARA TODOS LOS MODOS ------------------------------------------------------------\n let detector_flag = (flow.get(\"distance_flag_SET\") && (flow.get(\"sentido\") == \"entrada\") && flow.get(\"sensor_distancia_local\")) || false;\n let boton_flag = flow.get(\"salida_valida_flag\") || false;\n let matricula_flag = flow.get(\"matricula_ok_flag\") || false;\n let register_flag = flow.get(\"movimiento_registrado_flag\");\n let firma_flag = flow.get(\"firma_ok_flag\")\n let menu_activo = flow.get(\"menu_activo\") // el menu activo se configura en el archivo de configuracion\n let menu_selected = flow.get(\"menu_seleccionado_flag\") // este flag se activa cuando el conductor selecciona el residuo del menu y lo envia (en caso de menu_activo = true)\n let ID_verificado = flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")\n \n // Reglas de obligatoriedad configurables en archivo de configuracion\n\n let ID_obligatorio = flow.get(\"ID_obligatorio\")\n let detector_obligatorio = flow.get(\"detector_obligatorio\") || false; // este es el detector de presencia de vehiculo frente al totem\n let boton_obligatorio = flow.get(\"boton_obligatorio\") || false; // Este corresponde al boton de la pantalla de Validacion en caso de estar habilitado\n let firma_obligatoria = flow.get(\"firma_obligatoria\") || false;\n //let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || false\n let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || true // siempre es obligatoria\n \n // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n \n let ID_ok = !ID_obligatorio || ID_verificado\n let detector_ok = !detector_obligatorio || detector_flag;\n if (flow.get(\"tipo_movimiento\") == \"inicial\") { boton_flag = true } // en movimiento inicial no tiene sentido el boton\n let boton_ok = !boton_obligatorio || boton_flag;\n let firma_ok = !firma_obligatoria || firma_flag;\n //**************************************************** Excepcion para Trajeta RFID **************************************************\n //*********************************** No es necesario tener la matricula del Vehiculo ni poner boton de salida *******************************\n if (flow.get(\"RFID_verificado\")) { \n matricula_flag = true \n boton_ok = true\n }\n \n let matricula_ok = !matricula_obligatoria || matricula_flag\n let seleccion_ok\n if(flow.get(\"tipo_movimiento\") == \"inicial\"){\n seleccion_ok = !menu_activo || menu_selected || ID_verificado // Si el menu esta activo, el ID_verificado permite saltar la seleccion del residuo\n }\n else if(flow.get(\"tipo_movimiento\") == \"final\"){\n //seleccion_ok = !menu_activo || menu_selected || ID_verificado || boton_flag\n seleccion_ok = true\n ID_ok = !flow.get(\"salida_ID_obligatorio\") || ID_verificado\n }\n \n //************************ SOLICITUD DE UBICACION INTERNA Y NOTIFICACION AL CONDUCTOR ***************************************/\n // ****** OJO AQUI ***** Mientras \"ubicacion_recibida\" no cambie a true, es decir hasta que la BD no conteste el request, esto seguira enviando el request nuevamente\n // Es decir que si se pierde comunicacion esto enviara siempre que pueda entrar en este codigo.\n let requerimientos_ok = ID_ok && boton_ok && firma_ok && matricula_ok && seleccion_ok && flow.get(\"mostrar_ubicacion\") && !flow.get(\"mostrar_ubicacion_ok\") && (flow.get(\"tipo_movimiento\") === \"inicial\")\n node.warn(\"requerimientos_ok = \" + requerimientos_ok)\n node.warn(\"seleccion = \" + seleccion_ok + \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok + \" ; firma = \" + firma_ok + \" ; mostrar_ubicacion = \" + flow.get(\"mostrar_ubicacion\") + \" ; movimiento = \" + (flow.get(\"tipo_movimiento\") === \"inicial\"))\n \n if (requerimientos_ok) {\n if (!flow.get(\"ubicacion_recibida\")) { // Si aun no hemos recibido el aviso de la ubicacion, la solicitamos\n let id_residuo\n if (flow.get(\"last_QR\") != \"-\") { id_residuo = flow.get(\"last_QR\") }\n else if (flow.get(\"last_RFID\") != \"-\") { id_residuo = flow.get(\"last_RFID\") }\n else if (flow.get(\"id_seleccionado\") != \"no recibido\") { id_residuo = flow.get(\"id_seleccionado\") }\n msg.payload = { numero_vial: flow.get(\"numero_vial\"), totem_id: flow.get(\"totem_id\"), device: \"supervisor\", accion: \"check_ubicacion\", id_residuo: id_residuo }\n node.send([null, null, msg, null])\n node.warn(\"enviado solicitud de ubicacion\")\n }\n\n //if (flow.get(\"ubicacion_recibida\")) { // Con flow.get(\"mostrar_ubicacion_ok\") aseguramos que solo sacamos la notificacion una vez\n else {\n //Aqui sacamos notificacion al conductor\n\n flow.set(\"mostrar_ubicacion_ok\", true) //marcamos que ya hemos recibido respuesta del ubicacion\n if (!flow.get(\"ubicacion_interna\")) { // si no se ha recibido el flag de ubicacion interna en true es que no existe ubicacion especifica para ese residuo\n flow.set(\"dirigirse\", \"NO HAY UBICACION DEFINIDA\")\n }\n node.warn(\"DIRIGIRSE A : \" + flow.get(\"dirigirse\"))\n node.send([null, null, null, null, { // aqui envia,os la notificacion al conductor\n payload:\n \"
\" +\n \"

ATENCION

\" +\n \"

\" + flow.get(\"dirigirse\") + \"

\" +\n \"
\"\n }])\n\n }\n }\n if (flow.get(\"tipo_movimiento\") === \"final\") { flow.set(\"mostrar_ubicacion_ok\", true) }\n let ubicacion_ok = !flow.get(\"mostrar_ubicacion\") || flow.get(\"mostrar_ubicacion_ok\")\n //******************************************************************************************************************************************************** */\n \n \n let todos_obligatorios_ok;\n\n switch (modo) {\n\n case \"A\": //************************************** MODO A [ Matricula - QR / RFID - sensor local - boton de salida ]***************************************************** */\n // aqui revisamos si se recibio matricula y un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes eslementos:\n // - un QR o una tarjeta RFID\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // - la seleccion del menu\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que se active el semaforo en verde\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO (presente en la configuracion ) que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = ID_ok && detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && matricula_ok && ubicacion_ok;\n \n node.warn(\"todos obligatorios = \" + todos_obligatorios_ok)\n node.warn(\"ID_ok = \" + ID_ok + \" ; detector_ok = \" + detector_ok + \" ; register_flag = \" + register_flag + \" ; seleccion = \" + seleccion_ok + \n \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok + \" ; ubicacion = \" + ubicacion_ok )\n \n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n //node.warn(\"matricula ok\")\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n \n if (flow.get(\"tipo_movimiento\") == \"inicial\"){\n new_register.qr = flow.get(\"last_QR\")\n }\n else if (flow.get(\"tipo_movimiento\") == \"final\"){\n new_register.qrsalida = flow.get(\"last_QR\")\n }\n \n new_register.rfid = flow.get(\"last_RFID\")\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = flow.get(\"nombre_firma\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")){\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n if (!flow.get(\"movimiento_enviado\")){\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n //node.warn(\"revisando QR / RFID flags\")\n \n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || !flow.get(\"ID_obligatorio\")) {\n flow.set(\"window_men_m3\", \"\");\n }\n else {\n //node.warn(\"sacamos mensaje de identificacion\")\n flow.set(\"window_men_m3\", flow.get(\"men_identificacion\")); // solicitamos por pantalla una identificación de tipo QR o RFID\n }//-----------------------------------------------------------------------------------------------------------------------------------------\n break;\n\n case \"B\": //************************************** MODO B [ Matricula - sensor local - boton de salida ] *****************************************************\n // aqui revisamos si se recibio matricula y un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes elementos:\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento se actibve el semaforo en verde.\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && matricula_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n break;\n case \"C\": //************************************** MODO C [ QR / RFID - sensor local - boton de salida ]*****************************************************\n // aqui revisamos si se recibio un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes eslementos:\n // - un QR o una tarjeta RFID\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que se active el semaforo en verde.\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = ID_ok && detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = flow.get(\"last_QR\")\n new_register.rfid = flow.get(\"last_RFID\")\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || !flow.get(\"ID_obligatorio\")) {\n flow.set(\"window_men_m3\", \"\");\n }\n else {\n flow.set(\"window_men_m3\", flow.get(\"men_identificacion\"));\n }//-----------------------------------------------------------------------------------------------------------------------------------------\n\n break;\n case \"D\": //************************************** MODO D [boton de salida ]*****************************************************\n // aqui revisamos si se recibio el boton de validacion que indica que el conductor esta frente al totem\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que el semaforo se active en verde.\n boton_flag = flow.get(\"salida_valida_flag\") || false;\n\n boton_obligatorio = seleccion_ok && (flow.get(\"boton_obligatorio\") || false); // Este corresponde al boton de la pantalla de Validacion en caso de estar habilitado\n register_flag = flow.get(\"movimiento_registrado_flag\")\n\n // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n\n boton_ok = !boton_obligatorio || boton_flag;\n\n todos_obligatorios_ok = boton_ok && !register_flag && firma_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n\n break;\n\n }// termina el codigo del SWITCH CASE\n //*************************************************** PREPARACION Y ENVIO DEL MOVIMIENTO *******************************************************\n if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")&& !flow.get(\"movimiento_enviado\")) {\n let date = new Date();\n let timestamp = parseInt(date.getTime() / 1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n\n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n\n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")) { // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n flow.set(\"movimiento_registrado_flag\", false) // evitamos que podamos entrar en este espacio hasta nuevo registro\n\n // *********************** preparamos json con movimiento para enviar al supervisor local de la bascula *****************\n let msg_mov = { payload: {} }\n new_register.tara = flow.get(\"tara\")\n new_register.destareautomatico = flow.get(\"destareautomatico\")\n msg_mov.payload.device = \"supervisor\"\n msg_mov.payload.totem_id = flow.get(\"totem_id\")\n msg_mov.payload.accion = \"movimiento\"\n //msg_mov.payload.tipo = flow.get(\"modelo\") // entrada / salida\n msg_mov.payload.tipomovimiento = flow.get(\"tipo_movimiento\")\n //msg_mov.payload.urlapi = flow.get(\"url_API\")\n msg_mov.payload.movimiento = new_register // enviamos el registro del movimiento con las imagenes de matricula y de firma\n flow.set(\"movimiento_enviado\", true)\n flow.set(\"new_register\", {}) // inicializamos el registro para evitar cualquier posible duplicado en bd\n node.send([null, null, msg_mov, null])\n }\n\n }\n}\nreturn ([null, null, null, msg])", + "func": "//***************************** Selecciona Modo de Operacion **************************************************\nif (!flow.get(\"supervisor\")) {\n if (flow.get(\"peso_estable_flag\")) { //El peso estable se obtiene cuando el vehiculo esta frente al Totem (QR / RFID o sino Detector Local ON o bien pulsar un boton que aparezca en pantalla)\n if (flow.get(\"tipo_movimiento\") == \"final\") {\n flow.set(\"firma_ok_flag\", true) // indicamos que la firma esta hecha, esta no hace falta para la salida\n }\n let ID_verificado = flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")\n if (flow.get(\"firma_obligatoria\") && !flow.get(\"firma_flag\") &&!flow.get(\"firma_ok_flag\") && !flow.get(\"supervisor\") && (!flow.get(\"menu_activo\") || (flow.get(\"menu_activo\") && (flow.get(\"menu_seleccionado_flag\") || ID_verificado)))) { //chequea si tenemos que solicitar firma\n /*\n El if anterior se cumple si:\n - firma_obligatoria es true y firma_ok_flag es false y firma_flag es false y si supervisor es false y ademas si menu_activo es false o bien menu_activo es true y menu_seleccionado_flag es true (osea se ha seleccionado el menu)\n Con esto aseguramos que la firma la sacamos una vez que el usuario ha hecho la seleccion del menu (en caso de existir) y no antes.\n */\n // hemos cambiado \"firma_habilitada\" por \"firma_obligatoria\" porque finalmente con un solo parametro es suficiente\n // finalmente hacemos el llamado a la firma solamente durante el movimiento inicial\n if (flow.get(\"tipo_movimiento\") == \"inicial\") {\n flow.set(\"firma_flag\", true) // solicitud de firma\n setTimeout(() => {\n node.warn(\"solicitando firma\")\n node.send([{ \"payload\": { \"tab\": \"Firma\" } }, { payload: \"firma\" }, null, null, {payload:\"\"}])\n }, 2000);\n }\n /*\n else if (flow.get(\"tipo_movimiento\") == \"final\") {\n flow.set(\"firma_ok_flag\", true) // indicamos que la firma esta hecha, esta no hace falta para la salida\n }\n */\n }\n\n //=============================================================================================================================================\n //====================================================== MODO DE OPERACION ====================================================================\n //=============================================================================================================================================\n let modo = flow.get(\"modo_totem\")\n // -----------------------------------------------------COMUN PARA TODOS LOS MODOS ------------------------------------------------------------\n let detector_flag = (flow.get(\"distance_flag_SET\") && (flow.get(\"sentido\") == \"entrada\") && flow.get(\"sensor_distancia_local\")) || false;\n let boton_flag = flow.get(\"salida_valida_flag\") || false;\n let matricula_flag = flow.get(\"matricula_ok_flag\") || false;\n let register_flag = flow.get(\"movimiento_registrado_flag\"); //si true, indica que el movimiento ha sido enviado\n let firma_flag = flow.get(\"firma_ok_flag\")\n let menu_activo = flow.get(\"menu_activo\") // el menu activo se configura en el archivo de configuracion\n let menu_selected = flow.get(\"menu_seleccionado_flag\") // este flag se activa cuando el conductor selecciona el residuo del menu y lo envia (en caso de menu_activo = true)\n //let ID_verificado = flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")\n \n // Reglas de obligatoriedad configurables en archivo de configuracion\n\n let ID_obligatorio = flow.get(\"ID_obligatorio\")\n let detector_obligatorio = flow.get(\"detector_obligatorio\") || false; // este es el detector de presencia de vehiculo frente al totem\n let boton_obligatorio = flow.get(\"boton_obligatorio\") || false; // Este corresponde al boton de la pantalla de Validacion en caso de estar habilitado\n let firma_obligatoria = flow.get(\"firma_obligatoria\") || false;\n //let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || false\n let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || true // siempre es obligatoria\n \n // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n \n let ID_ok = !ID_obligatorio || ID_verificado\n let detector_ok = !detector_obligatorio || detector_flag;\n if (flow.get(\"tipo_movimiento\") == \"inicial\") { boton_flag = true } // en movimiento inicial no tiene sentido el boton\n let boton_ok = !boton_obligatorio || boton_flag;\n let firma_ok = !firma_obligatoria || firma_flag;\n //**************************************************** Excepcion para Trajeta RFID **************************************************\n //*********************************** No es necesario tener la matricula del Vehiculo ni poner boton de salida *******************************\n if (flow.get(\"RFID_verificado\")) { \n matricula_flag = true \n boton_ok = true\n }\n \n let matricula_ok = !matricula_obligatoria || matricula_flag\n let seleccion_ok\n if(flow.get(\"tipo_movimiento\") == \"inicial\"){\n seleccion_ok = !menu_activo || menu_selected || ID_verificado // Si el menu esta activo, el ID_verificado permite saltar la seleccion del residuo\n\n if (ID_verificado && menu_activo) {\n // ==================== eliminamos mensaje y boton del menu debido a que tenemos ID del residuo (Tarjeta o QR) ================================\n flow.set(\"startmenu_flag\", false) // para poder eliminar el boton y borrar el mensaje em \"window_men_m1\"\n flow.set(\"window_men_m1\", \"\") // colocamos mensaje vacio en el espacio del mensaje 1 donde decia Haga click Abajo\n }\n }\n else if(flow.get(\"tipo_movimiento\") == \"final\"){\n //seleccion_ok = !menu_activo || menu_selected || ID_verificado || boton_flag\n seleccion_ok = true\n ID_ok = !flow.get(\"salida_ID_obligatorio\") || ID_verificado\n }\n \n //************************ SOLICITUD DE UBICACION INTERNA Y NOTIFICACION AL CONDUCTOR ***************************************/\n // ****** OJO AQUI ***** Mientras \"ubicacion_recibida\" no cambie a true, es decir hasta que la BD no conteste el request, esto seguira enviando el request nuevamente\n // Es decir que si se pierde comunicacion esto enviara siempre que pueda entrar en este codigo.\n let requerimientos_ok = ID_ok && boton_ok && firma_ok && matricula_ok && seleccion_ok && flow.get(\"mostrar_ubicacion\") && !flow.get(\"mostrar_ubicacion_ok\") && (flow.get(\"tipo_movimiento\") === \"inicial\")\n node.warn(\"requerimientos_ok = \" + requerimientos_ok)\n node.warn(\"seleccion = \" + seleccion_ok + \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok + \" ; firma = \" + firma_ok + \" ; mostrar_ubicacion = \" + flow.get(\"mostrar_ubicacion\") + \" ; movimiento = \" + (flow.get(\"tipo_movimiento\") === \"inicial\"))\n \n if (requerimientos_ok) {\n if (!flow.get(\"ubicacion_recibida\")) { // Si aun no hemos recibido el aviso de la ubicacion, la solicitamos\n let id_residuo\n if (flow.get(\"last_QR\") != \"-\") { id_residuo = flow.get(\"last_QR\") }\n else if (flow.get(\"last_RFID\") != \"-\") { id_residuo = flow.get(\"last_RFID\") }\n else if (flow.get(\"id_seleccionado\") != \"no recibido\") { id_residuo = flow.get(\"id_seleccionado\") }\n msg.payload = { numero_vial: flow.get(\"numero_vial\"), totem_id: flow.get(\"totem_id\"), device: \"supervisor\", accion: \"check_ubicacion\", id_residuo: id_residuo }\n node.send([null, null, msg, null])\n node.warn(\"enviado solicitud de ubicacion\")\n }\n\n //if (flow.get(\"ubicacion_recibida\")) { // Con flow.get(\"mostrar_ubicacion_ok\") aseguramos que solo sacamos la notificacion una vez\n else {\n //Aqui sacamos notificacion al conductor\n\n flow.set(\"mostrar_ubicacion_ok\", true) //marcamos que ya hemos recibido respuesta del ubicacion\n if (!flow.get(\"ubicacion_interna\")) { // si no se ha recibido el flag de ubicacion interna en true es que no existe ubicacion especifica para ese residuo\n flow.set(\"dirigirse\", \"NO HAY UBICACION DEFINIDA\")\n }\n node.warn(\"DIRIGIRSE A : \" + flow.get(\"dirigirse\"))// aqui enviamos la notificacion al conductor\n node.send([null, null, null, null, { \n payload:\n \"
\" +\n \"

ATENCION

\" +\n \"

\" + flow.get(\"dirigirse\") + \"

\" +\n \"
\"\n }])\n\n }\n }\n if (flow.get(\"tipo_movimiento\") === \"final\") { flow.set(\"mostrar_ubicacion_ok\", true) }\n let ubicacion_ok = !flow.get(\"mostrar_ubicacion\") || flow.get(\"mostrar_ubicacion_ok\")\n //******************************************************************************************************************************************************** */\n \n \n let todos_obligatorios_ok;\n\n switch (modo) {\n\n case \"A\": //************************************** MODO A [ Matricula - QR / RFID - sensor local - boton de salida ]***************************************************** */\n // aqui revisamos si se recibio matricula y un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes eslementos:\n // - un QR o una tarjeta RFID\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // - la seleccion del menu\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que se active el semaforo en verde\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO (presente en la configuracion ) que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = ID_ok && detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && matricula_ok && ubicacion_ok;\n //OJO \"register_flag\" debe ser false lo cual indica que aun no hemos enviado el movimiento.\n node.warn(\"todos obligatorios = \" + todos_obligatorios_ok)\n node.warn(\"ID_ok = \" + ID_ok + \" ; detector_ok = \" + detector_ok + \" ; register_flag = \" + register_flag + \" ; seleccion = \" + seleccion_ok + \n \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok + \" ; ubicacion = \" + ubicacion_ok )\n \n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n //node.warn(\"matricula ok\")\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n new_register.qr = flow.get(\"last_QR\")\n /*\n if (flow.get(\"tipo_movimiento\") == \"inicial\"){\n new_register.qr = flow.get(\"last_QR\")\n }\n else if (flow.get(\"tipo_movimiento\") == \"final\"){\n new_register.qrsalida = flow.get(\"last_QR\")\n }\n */\n new_register.rfid = flow.get(\"last_RFID\")\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = flow.get(\"nombre_firma\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")){\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n if (!flow.get(\"movimiento_enviado\")){\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n //node.warn(\"revisando QR / RFID flags\")\n \n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || !flow.get(\"ID_obligatorio\")) {\n flow.set(\"window_men_m3\", \"\");\n }\n else {\n //node.warn(\"sacamos mensaje de identificacion\")\n flow.set(\"window_men_m3\", flow.get(\"men_identificacion\")); // solicitamos por pantalla una identificación de tipo QR o RFID\n }//-----------------------------------------------------------------------------------------------------------------------------------------\n break;\n\n case \"B\": //************************************** MODO B [ Matricula - sensor local - boton de salida ] *****************************************************\n // aqui revisamos si se recibio matricula y un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes elementos:\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento se actibve el semaforo en verde.\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && matricula_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n break;\n case \"C\": //************************************** MODO C [ QR / RFID - sensor local - boton de salida ]*****************************************************\n // aqui revisamos si se recibio un evento que indique que el conductor esta frente al totem\n // puede ser alguno de los siguientes eslementos:\n // - un QR o una tarjeta RFID\n // - el boton de activacion de salida que ponemos en pantalla en caso de estar habilitado para ello en el archivo de configuración\n // - el sensor local de presencia de vehiculo\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que se active el semaforo en verde.\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO que se deba recibir antes de dar por finalizada la pesada. \n // Un evento obligatorio podria ser La tarjeta RFID o el QR o pulsar el boton de Validacion\n\n todos_obligatorios_ok = ID_ok && detector_ok && boton_ok && seleccion_ok && !register_flag && firma_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = flow.get(\"last_QR\")\n new_register.rfid = flow.get(\"last_RFID\")\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || !flow.get(\"ID_obligatorio\")) {\n flow.set(\"window_men_m3\", \"\");\n }\n else {\n flow.set(\"window_men_m3\", flow.get(\"men_identificacion\"));\n }//-----------------------------------------------------------------------------------------------------------------------------------------\n\n break;\n case \"D\": //************************************** MODO D [boton de salida ]*****************************************************\n // aqui revisamos si se recibio el boton de validacion que indica que el conductor esta frente al totem\n // El flag movimiento_registrado_flag se revisa para asegurar que se registra una sola vez al cumplir las condiciones\n // El registro queda en memoria, este se pasa a BD solamente al momento que el semaforo se active en verde.\n boton_flag = flow.get(\"salida_valida_flag\") || false;\n\n boton_obligatorio = seleccion_ok && (flow.get(\"boton_obligatorio\") || false); // Este corresponde al boton de la pantalla de Validacion en caso de estar habilitado\n register_flag = flow.get(\"movimiento_registrado_flag\")\n\n // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n\n boton_ok = !boton_obligatorio || boton_flag;\n\n todos_obligatorios_ok = boton_ok && !register_flag && firma_ok && ubicacion_ok;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n\n break;\n\n }// termina el codigo del SWITCH CASE\n //*************************************************** PREPARACION Y ENVIO DEL MOVIMIENTO *******************************************************\n if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")&& !flow.get(\"movimiento_enviado\")) {\n let date = new Date();\n let timestamp = parseInt(date.getTime() / 1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n\n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n\n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")) { // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n flow.set(\"movimiento_registrado_flag\", false) // evitamos que podamos entrar en este espacio hasta nuevo registro\n\n // *********************** preparamos json con movimiento para enviar al supervisor local de la bascula *****************\n let msg_mov = { payload: {} }\n new_register.tara = flow.get(\"tara\")\n new_register.destareautomatico = flow.get(\"destareautomatico\")\n msg_mov.payload.device = \"supervisor\"\n msg_mov.payload.totem_id = flow.get(\"totem_id\")\n msg_mov.payload.accion = \"movimiento\"\n //msg_mov.payload.tipo = flow.get(\"modelo\") // entrada / salida\n msg_mov.payload.tipomovimiento = flow.get(\"tipo_movimiento\")\n //msg_mov.payload.urlapi = flow.get(\"url_API\")\n msg_mov.payload.movimiento = new_register // enviamos el registro del movimiento con las imagenes de matricula y de firma\n flow.set(\"movimiento_enviado\", true)\n flow.set(\"new_register\", {}) // inicializamos el registro para evitar cualquier posible duplicado en bd\n node.send([null, null, msg_mov, null])\n }\n\n }\n}\nreturn ([null, null, null, msg, null])", "outputs": 5, "timeout": 0, "noerr": 0, @@ -4299,7 +4307,9 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "entrada json", - "links": [], + "links": [ + "41b4309de63a6bba" + ], "x": 415, "y": 1260, "wires": [ @@ -4523,7 +4533,7 @@ "payload": "E0820D8C-22F8-42E7-B58F-2C4CC288FD3E", "payloadType": "str", "x": 2700, - "y": 1800, + "y": 1920, "wires": [ [ "120a33aec5cdad35" @@ -4558,7 +4568,7 @@ "to": "", "reg": false, "x": 2920, - "y": 1740, + "y": 1860, "wires": [ [] ] @@ -4586,7 +4596,7 @@ "payload": "true", "payloadType": "bool", "x": 2720, - "y": 1700, + "y": 1820, "wires": [ [ "25d47d91059e756a", @@ -4617,7 +4627,7 @@ "payload": "false", "payloadType": "bool", "x": 2710, - "y": 1740, + "y": 1860, "wires": [ [ "25d47d91059e756a" @@ -4663,7 +4673,7 @@ "03abdad8b6e3e504" ], "x": 3045, - "y": 1920, + "y": 2040, "wires": [] }, { @@ -4680,7 +4690,7 @@ "finalize": "", "libs": [], "x": 2770, - "y": 2140, + "y": 2260, "wires": [ [] ] @@ -4695,7 +4705,7 @@ "b890981ca603e6e1" ], "x": 2645, - "y": 2140, + "y": 2260, "wires": [ [ "bc10f90fd35fca2a" @@ -4713,7 +4723,7 @@ "e0b4dd6107f95f28" ], "x": 2875, - "y": 1700, + "y": 1820, "wires": [] }, { @@ -4740,7 +4750,7 @@ "payload": "763cdffa", "payloadType": "str", "x": 2710, - "y": 2100, + "y": 2220, "wires": [ [ "120a33aec5cdad35" @@ -4786,7 +4796,7 @@ "name": "Modo A = (QR or RFID or Distance or Boton) and Matricula", "info": "", "x": 2770, - "y": 2240, + "y": 2360, "wires": [] }, { @@ -4797,7 +4807,7 @@ "name": "Modo B = (Distance or Boton) and Matricula", "info": "", "x": 2730, - "y": 2280, + "y": 2400, "wires": [] }, { @@ -4808,7 +4818,7 @@ "name": "Modo C = QR or RFID or Boton", "info": "", "x": 2690, - "y": 2320, + "y": 2440, "wires": [] }, { @@ -4819,7 +4829,7 @@ "name": "Modo D = Boton", "info": "", "x": 2640, - "y": 2360, + "y": 2480, "wires": [] }, { @@ -4846,7 +4856,7 @@ "payload": "546DA2A4-C456-482D-B98F-B4EB0FFABB0E", "payloadType": "str", "x": 2700, - "y": 1840, + "y": 1960, "wires": [ [ "120a33aec5cdad35" @@ -4877,7 +4887,7 @@ "payload": "12345678", "payloadType": "str", "x": 2710, - "y": 1980, + "y": 2100, "wires": [ [ "120a33aec5cdad35" @@ -4907,7 +4917,7 @@ "payload": "{\"totem_id\":\"totem_2\",\"sentido\":\"Entrada en bascula\",\"topic\":\"detector_ON\",\"input_flag\":true}", "payloadType": "json", "x": 2700, - "y": 1640, + "y": 1760, "wires": [ [ "de4c24109d3a3cec" @@ -4925,7 +4935,7 @@ "85fe3844a73d42e6" ], "x": 2895, - "y": 1640, + "y": 1760, "wires": [] }, { @@ -4949,10 +4959,10 @@ "once": false, "onceDelay": 0.1, "topic": "", - "payload": "bd2dfc2", + "payload": "763ccd5a", "payloadType": "str", "x": 2710, - "y": 2020, + "y": 2140, "wires": [ [ "120a33aec5cdad35" @@ -4983,7 +4993,7 @@ "payload": "987654321", "payloadType": "str", "x": 2710, - "y": 2060, + "y": 2180, "wires": [ [ "120a33aec5cdad35" @@ -5066,7 +5076,7 @@ "title": "", "descr": "", "editurl": "vscode://vscode-remote/ssh-remote+192.168.0.29/home/trypton/.node-red/projects/Bascula_Autonoma_1/uibuilder/totem/?windowId=_blank", - "x": 3720, + "x": 3860, "y": 2200, "wires": [ [ @@ -5098,7 +5108,7 @@ "topic": "", "payload": "{\"payload\":{\"pantalla\":\"menu-principal\"}}", "payloadType": "json", - "x": 3550, + "x": 3690, "y": 2080, "wires": [ [ @@ -5112,14 +5122,14 @@ "z": "953e8740401d175c", "g": "e3bc37824e09b774", "name": "buttons \\n decoder", - "func": "\nif (msg.topic === \"tipoconfig\"){\n let tiposDatosGlobal = flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []};\n\nconst tipo = msg.payload.tipo; // ej: 2\nconst datos = msg.payload.datos; // array con los parámetros\n\ntiposDatosGlobal[tipo] = datos;\n\nflow.set(\"tiposDatosGlobal\", tiposDatosGlobal);\n\nreturn ;\n}\nelse if (msg.payload.hasOwnProperty(\"seccion\")) {\n\n\n /* Los diferentes \"case\" corresponden a la pulsacion de botones de los diferentes menus de configuracion\n Cada menu solicitado mediante el click de un boton devuelve el nombre del \"div\" en el archivo html que debemos habilitar\n para que se muestre en pantalla.\n Si la entrada no consigue ningun case que se ajuste entonces caemos en el \"default\" y ahi buscamos primero si hay\n algun mensaje en \"origen\", lo que corresponde a la actualizacion de alguna de las tablas dinamicas que se generan\n para modificar cada tipo de parametro. Luego se revisan los \"modalCallback\" los cuales no indican que la respuesta\n de la notificacion de alguna accion importante ha sido positiva (\"SI\").\n \n */\n\n switch (msg.payload.seccion) {\n\n case \"menu-principal\": // boton de configuracion en pantalla principal para acceder al menu principal \n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"editar\": // boton para acceder al menu de edicion de la configuracion\n return { payload: { pantalla: \"editar\" } }\n\n case \"pruebas\": // boton para acceder al menu de pruebas del sistema\n return { payload: { pantalla: \"pruebas\" } }\n\n case \"semaforo\": // boton para acceder al menu prueba del semaforo\n return { payload: { pantalla: \"semaforo\" } }\n\n case \"otras\": // boton para acceder al menu de otras acciones\n return { payload: { pantalla: \"otras\" } }\n\n case \"regresar\": // boton para regresar al menu principal desde otras acciones y desde menu de pruebas del sistema\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"salvar\": // boton para almacenar los cambios en el archivo de configuracion en el menu de edicion de la configuracion\n return ([{ payload: { pantalla: \"editar\" }, modalText: \"Desea MODIFICAR el archivo de CONFIGURACION ?\", modalCallback: \"modificar\" }, null, null, null])\n\n case \"cancelar\": // boton para cancelar y salir del menu de editar configuracion\n return ([{ payload: { pantalla: \"menu-principal\" } }, null])\n\n case \"semaforo_on\": // boton para poner el semaforo en rojo\n flow.set(\"semaforo\", \"red\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"firebrick\" }, null, { payload: 0 }])\n\n case \"semaforo_off\": // boton para poner el semaforo en verde\n flow.set(\"semaforo\", \"green\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"green\" }, null, { payload: 1 }])\n\n case \"salir-semaforo\": // boton de salida de la pantalla de prueba del semaforo\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"barrera\": // boton de activar barrera\n return ({ payload: { pantalla: \"barrera\" }, barrera: false })\n\n case \"general\": // boton para ver / modificar tabla con los parametros generales\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"general\", tabla: flow.get(\"config_general\") }, null, null])\n\n case \"camara\": // boton para ver / modificar tabla con los parametros de la camara\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"camara\", tabla: flow.get(\"config_camara\") }, null, null])\n\n case \"conexion\": // boton para ver / modificar tabla con los parametros de conexion\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"conexion\", tabla: flow.get(\"config_conex\") }, null, null])\n\n case \"sensores\": // boton para ver / modificar tabla con los parametros de sensores\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"sensores\", tabla: flow.get(\"config_sensor\") }, null, null])\n\n case \"mensajes\": // boton para ver / modificar tabla con los parametros de los mensajes\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"mensajes\", tabla: flow.get(\"config_mensajes\") }, null, null])\n\n case \"tiempos\": // boton para ver / modificar tabla con los parametros del tiempo\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"tiempos\", tabla: flow.get(\"config_tiempos\") }, null, null])\n\n case \"aplicar\": // boton para aplicar la configuracion al RPi, en el menu-principal\n return ([{ payload: { pantalla: \"menu-principal\" }, topic: \"menu-principal\", modalText: \"Desea Recargar la CONFIGURACION ?\", modalCallback: \"recargar\" }, null, null])\n\n case \"reboot\": // boton para resetear el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea Reiniciar el TOTEM ?\", modalCallback: \"reiniciar\" }, null, null])\n\n case \"apagar\": // boton para apagar el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea APAGAR el TOTEM ?\", modalCallback: \"apagar\" }, null, null])\n\n case \"snapshot\": // boton para pedir snapshot\n flow.set(\"snapshot_cam\", true)\n flow.set(\"escuchar_cam\", false)\n let msgrqt = {}\n msgrqt.payload = {}\n msgrqt.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n msgrqt.topic = \"snapshot_rqtd\"\n return ([{ payload: { pantalla: \"snapshot\" }, topic: \"snapshot\" }, null, null, null, null, msgrqt])\n\n case \"escuchar\": // boton para escuchar camara ( recibir todas la imagenes que envie)\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", true)\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"left\": // Boton para ir a la imagen anterior en escuchar camara\n flow.set(\"getfromarray\", \"left\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"right\": // Boton para ir a la siguiente imagen en escuchar camara\n flow.set(\"getfromarray\", \"right\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"salir-snapshot\": // boton de salida de la pantalla de ver snapshot\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"salir-barrera\": // boton de salida de la barrera\n\n return ({ payload: { pantalla: \"pruebas\" }, barrera: false })\n\n case \"salir-escuchar\": // boton de salida de la pantalla de escuchar la camara\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n flow.set(\"snapshot_array\", [])\n flow.set(\"snapshot_readindex\", 0)\n flow.set(\"snapshot_saveindex\", 0)\n flow.set(\"snapshot_indexmax\", 0)\n flow.set(\"getfromarray\", \"\")\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"activar-barrera\": // boton de activar barrera\n node.send([{ payload: { pantalla: \"barrera\" }, barrera: true }, null, null, null, null, null, null, { payload: 0 }])\n setTimeout(function () {\n node.send([null, null, null, null, null, null, null, { payload: 1 }])\n }, flow.get(\"relay2_pulse\"));\n return\n\n case \"cancel-table\": // boton de CANCEL de las tablas de configuracion de parametros\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"salir\": // boton de salida del menu principal\n return ({ payload: { pantalla: \"principal\" } })\n\n case \"tipos\": // boton de salida al menu editar\n msg.payload = {pantalla: \"tipos\", tiposDatos: flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []}};\n return (msg)\n\n case \"volver_tipos\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"ayuda\" } })\n\n case \"salir-ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n default: // chequeamos si tenemos acciones a realizar para lo cual revisamos el \"origen\" (actualizar en memoria sin preguntar usuario) y/o el \"modalCallback\" con esto sabemos de que tabla es el mensaje enviado por el MODAL\n node.send([null, null, null, null, null, null, msg])\n if (msg.origen == \"actualizar\") {// salvar en memoria la configuracion que ha sido modificada (el Topic nos dice cual configuracion)\n let myconfig = msg.payload.table // table contiene el resultado de leer la tabla con todos los valores normalizados en uibuilder\n \n switch (msg.topic) { // guardamos cambios en el tipo de configuracion correspondiente\n case \"general\":\n flow.set(\"config_general\", myconfig)\n break;\n case \"conexion\":\n // ==================================== VALIDAMOS todas las IP de la configuracion ==================================================\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n \n if (validarIP(myconfig[1].valor)){\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del DISPOSITIVO NO es correcta ?\", modalType:\"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[2].valor)) {\n //node.warn(\"valor 2 = \" + myconfig[2].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del ROUTER NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[5].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del WEBSOCKET NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[12].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del TOTEM pareja NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n break;\n case \"camara\":\n flow.set(\"config_camara\", myconfig)\n break;\n case \"sensores\":\n flow.set(\"config_sensor\", myconfig)\n break;\n case \"tiempos\":\n flow.set(\"config_tiempos\", myconfig)\n break;\n case \"mensajes\":\n flow.set(\"config_mensajes\", myconfig)\n break;\n }\n return { payload: { pantalla: \"editar\" } }\n }\n\n \n msg.hello = \"hello 3\"\n node.send([null, null, null, null, null, null, msg])\n return null\n\n }\n} // final del SWITCH\nelse if (msg.modalCallback == \"modificar\") {\n /*\n let config_totem = []\n config_totem = flow.get(\"config_general\").concat(flow.get(\"config_camara\"), flow.get(\"config_conex\"), flow.get(\"config_sensor\"), flow.get(\"config_mensajes\"), flow.get(\"config_tiempos\"), flow.get(\"tiposDatosGlobal\"))\n flow.set(\"config_totem\", config_totem)\n let jsontest = toJson(flow.get(\"config_totem\"));\n */\n let config_totem = {\n general: flow.get(\"config_general\") || [],\n camara: flow.get(\"config_camara\") || [],\n conexion: flow.get(\"config_conex\") || [],\n sensores: flow.get(\"config_sensor\") || [],\n mensajes: flow.get(\"config_mensajes\") || [],\n tiempos: flow.get(\"config_tiempos\") || [],\n tipos: flow.get(\"tiposDatosGlobal\") || {}\n };\n\n flow.set(\"config_totem\", config_totem);\n\n msg.payload = JSON.stringify(config_totem, null, 2) + \"\\n\\r\";\n //msg.payload = JSON.stringify(jsontest, null, 2) + \"\\n\\r\"; // el factor 2 agrega 2 espacio al inicio de cada elemento\n //y agrega tambien una linea lo cual es interesante para la legibilidad del formato y para que los clientes SFTP puedan\n //leer bien el archivo, como es el caso de Mobaxterm.\n\n return ([{ payload: { pantalla: \"menu-principal\" } }, msg, null])\n}\nelse if (msg.modalCallback == \"recargar\") {\n return ([null, null, null, { payload: 1 }])\n}\n\nelse if (msg.modalCallback == \"reiniciar\") {\n return ([null, null, null, null, { payload: \"sudo shutdown -r now\" }])\n}\n\nelse if (msg.modalCallback == \"apagar\") {\n return ([null, null, null, null, { payload: \"sudo poweroff\" }])\n}\n\n//============================================== FUNCIONES ==============================================================\n//esta funcion convierte un array con elementos [parametro, valor] en un objeto Json respetando los tipos de parametro (numerico, booleano, texto)\nfunction toJson(data) {\n let newJson = {}\n /*\n data.forEach(item => {\n let param = item.parametro;\n let value = item.valor;\n */\n for (let i = 0; i < data.length; i++) {\n let param = data[i].parametro;\n let value = data[i].valor;\n\n // Parseo de tipos igual que antes\n if (typeof value === 'string') {\n if (value.toLowerCase() === \"true\") {\n newJson[param] = true;\n } else if (value.toLowerCase() === \"false\") {\n newJson[param] = false;\n } else if (!isNaN(value) && value.trim() !== \"\") {\n newJson[param] = Number(value);\n } else {\n newJson[param] = value;\n }\n } else {\n // Por si el value ya viene como booleano o número real\n newJson[param] = value;\n }\n }\n return (newJson)\n}\n\n//=======================================================================================================================================\n\nfunction validarIP(ip) {\n const regex = /^(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/;\n return regex.test(ip);\n}", + "func": "\nif (msg.topic === \"tipoconfig\"){\n let tiposDatosGlobal = flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []};\n\nconst tipo = msg.payload.tipo; // ej: 2\nconst datos = msg.payload.datos; // array con los parámetros\n\ntiposDatosGlobal[tipo] = datos;\n\nflow.set(\"tiposDatosGlobal\", tiposDatosGlobal);\n\nreturn ;\n}\nelse if (msg.payload.hasOwnProperty(\"seccion\")) {\n\n\n /* Los diferentes \"case\" corresponden a la pulsacion de botones de los diferentes menus de configuracion\n Cada menu solicitado mediante el click de un boton devuelve el nombre del \"div\" en el archivo html que debemos habilitar\n para que se muestre en pantalla.\n Si la entrada no consigue ningun case que se ajuste entonces caemos en el \"default\" y ahi buscamos primero si hay\n algun mensaje en \"origen\", lo que corresponde a la actualizacion de alguna de las tablas dinamicas que se generan\n para modificar cada tipo de parametro. Luego se revisan los \"modalCallback\" los cuales no indican que la respuesta\n de la notificacion de alguna accion importante ha sido positiva (\"SI\").\n \n */\n\n switch (msg.payload.seccion) {\n\n case \"menu-principal\": // boton de configuracion en pantalla principal para acceder al menu principal \n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"editar\": // boton para acceder al menu de edicion de la configuracion\n return { payload: { pantalla: \"editar\" } }\n\n case \"pruebas\": // boton para acceder al menu de pruebas del sistema\n return { payload: { pantalla: \"pruebas\" } }\n\n case \"semaforo\": // boton para acceder al menu prueba del semaforo\n return { payload: { pantalla: \"semaforo\" } }\n\n case \"otras\": // boton para acceder al menu de otras acciones\n return { payload: { pantalla: \"otras\" } }\n\n case \"regresar\": // boton para regresar al menu principal desde otras acciones y desde menu de pruebas del sistema\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"salvar\": // boton para almacenar los cambios en el archivo de configuracion en el menu de edicion de la configuracion\n return ([{ payload: { pantalla: \"editar\" }, modalText: \"Desea MODIFICAR el archivo de CONFIGURACION ?\", modalCallback: \"modificar\" }, null, null, null])\n\n case \"cancelar\": // boton para cancelar y salir del menu de editar configuracion\n return ([{ payload: { pantalla: \"menu-principal\" } }, null])\n\n case \"semaforo_on\": // boton para poner el semaforo en rojo\n flow.set(\"semaforo\", \"red\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"firebrick\" }, null, { payload: 0 }])\n\n case \"semaforo_off\": // boton para poner el semaforo en verde\n flow.set(\"semaforo\", \"green\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"green\" }, null, { payload: 1 }])\n\n case \"salir-semaforo\": // boton de salida de la pantalla de prueba del semaforo\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"barrera\": // boton de activar barrera\n return ({ payload: { pantalla: \"barrera\" }, barrera: false })\n\n case \"general\": // boton para ver / modificar tabla con los parametros generales\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"general\", tabla: flow.get(\"config_general\") }, null, null])\n\n case \"camara\": // boton para ver / modificar tabla con los parametros de la camara\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"camara\", tabla: flow.get(\"config_camara\") }, null, null])\n\n case \"conexion\": // boton para ver / modificar tabla con los parametros de conexion\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"conexion\", tabla: flow.get(\"config_conex\") }, null, null])\n\n case \"sensores\": // boton para ver / modificar tabla con los parametros de sensores\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"sensores\", tabla: flow.get(\"config_sensor\") }, null, null])\n\n case \"mensajes\": // boton para ver / modificar tabla con los parametros de los mensajes\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"mensajes\", tabla: flow.get(\"config_mensajes\") }, null, null])\n\n case \"tiempos\": // boton para ver / modificar tabla con los parametros del tiempo\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"tiempos\", tabla: flow.get(\"config_tiempos\") }, null, null])\n\n case \"aplicar\": // boton para aplicar la configuracion al RPi, en el menu-principal\n return ([{ payload: { pantalla: \"menu-principal\" }, topic: \"menu-principal\", modalText: \"Desea Recargar la CONFIGURACION ?\", modalCallback: \"recargar\" }, null, null])\n\n case \"reboot\": // boton para resetear el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea Reiniciar el TOTEM ?\", modalCallback: \"reiniciar\" }, null, null])\n\n case \"apagar\": // boton para apagar el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea APAGAR el TOTEM ?\", modalCallback: \"apagar\" }, null, null])\n\n case \"snapshot\": // boton para pedir snapshot\n flow.set(\"snapshot_cam\", true)\n flow.set(\"escuchar_cam\", false)\n let msgrqt = {}\n msgrqt.payload = {}\n msgrqt.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n msgrqt.topic = \"snapshot_rqtd\"\n return ([{ payload: { pantalla: \"snapshot\" }, topic: \"snapshot\" }, null, null, null, null, msgrqt])\n\n case \"escuchar\": // boton para escuchar camara ( recibir todas la imagenes que envie)\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", true)\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"left\": // Boton para ir a la imagen anterior en escuchar camara\n flow.set(\"getfromarray\", \"left\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"right\": // Boton para ir a la siguiente imagen en escuchar camara\n flow.set(\"getfromarray\", \"right\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"salir-snapshot\": // boton de salida de la pantalla de ver snapshot\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"salir-barrera\": // boton de salida de la barrera\n\n return ({ payload: { pantalla: \"pruebas\" }, barrera: false })\n\n case \"salir-escuchar\": // boton de salida de la pantalla de escuchar la camara\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n flow.set(\"snapshot_array\", [])\n flow.set(\"snapshot_readindex\", 0)\n flow.set(\"snapshot_saveindex\", 0)\n flow.set(\"snapshot_indexmax\", 0)\n flow.set(\"getfromarray\", \"\")\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"activar-barrera\": // boton de activar barrera\n node.send([{ payload: { pantalla: \"barrera\" }, barrera: true }, null, null, null, null, null, null, { payload: 0 }])\n setTimeout(function () {\n node.send([null, null, null, null, null, null, null, { payload: 1 }])\n }, flow.get(\"relay2_pulse\"));\n return\n\n case \"cancel-table\": // boton de CANCEL de las tablas de configuracion de parametros\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"salir\": // boton de salida del menu principal\n return ({ payload: { pantalla: \"principal\" } })\n\n case \"tipos\": // boton de salida al menu editar\n msg.payload = {pantalla: \"tipos\", tiposDatos: flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []}};\n return (msg)\n\n case \"volver_tipos\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"ayuda\" } })\n\n case \"salir-ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n //------------------Añadido por david--------------------------\n case \"sensor\": // boton para acceder al menu de prueba del sensor\n flow.set(\"display_detector\", true)\n return ({ payload: { pantalla: \"sensor\" } })\n\n case \"salir-sensor\": // boton de salida de la pantalla de prueba del sensor\n flow.set(\"display_detector\", false)\n return ({ payload: { pantalla: \"pruebas\" } })\n //---------------Fin añadido por david-------------\n \n default: // chequeamos si tenemos acciones a realizar para lo cual revisamos el \"origen\" (actualizar en memoria sin preguntar usuario) y/o el \"modalCallback\" con esto sabemos de que tabla es el mensaje enviado por el MODAL\n node.send([null, null, null, null, null, null, msg])\n if (msg.origen == \"actualizar\") {// salvar en memoria la configuracion que ha sido modificada (el Topic nos dice cual configuracion)\n let myconfig = msg.payload.table // table contiene el resultado de leer la tabla con todos los valores normalizados en uibuilder\n \n switch (msg.topic) { // guardamos cambios en el tipo de configuracion correspondiente\n case \"general\":\n flow.set(\"config_general\", myconfig)\n break;\n case \"conexion\":\n // ==================================== VALIDAMOS todas las IP de la configuracion ==================================================\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n \n if (validarIP(myconfig[1].valor)){\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del DISPOSITIVO NO es correcta ?\", modalType:\"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[2].valor)) {\n //node.warn(\"valor 2 = \" + myconfig[2].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del ROUTER NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[5].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del WEBSOCKET NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[12].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del TOTEM pareja NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n break;\n case \"camara\":\n flow.set(\"config_camara\", myconfig)\n break;\n case \"sensores\":\n flow.set(\"config_sensor\", myconfig)\n break;\n case \"tiempos\":\n flow.set(\"config_tiempos\", myconfig)\n break;\n case \"mensajes\":\n flow.set(\"config_mensajes\", myconfig)\n break;\n }\n return { payload: { pantalla: \"editar\" } }\n }\n\n \n msg.hello = \"hello 3\"\n node.send([null, null, null, null, null, null, msg])\n return null\n\n }\n} // final del SWITCH\nelse if (msg.modalCallback == \"modificar\") {\n /*\n let config_totem = []\n config_totem = flow.get(\"config_general\").concat(flow.get(\"config_camara\"), flow.get(\"config_conex\"), flow.get(\"config_sensor\"), flow.get(\"config_mensajes\"), flow.get(\"config_tiempos\"), flow.get(\"tiposDatosGlobal\"))\n flow.set(\"config_totem\", config_totem)\n let jsontest = toJson(flow.get(\"config_totem\"));\n */\n let config_totem = {\n general: flow.get(\"config_general\") || [],\n camara: flow.get(\"config_camara\") || [],\n conexion: flow.get(\"config_conex\") || [],\n sensores: flow.get(\"config_sensor\") || [],\n mensajes: flow.get(\"config_mensajes\") || [],\n tiempos: flow.get(\"config_tiempos\") || [],\n tipos: flow.get(\"tiposDatosGlobal\") || {}\n };\n\n flow.set(\"config_totem\", config_totem);\n\n msg.payload = JSON.stringify(config_totem, null, 2) + \"\\n\\r\";\n //msg.payload = JSON.stringify(jsontest, null, 2) + \"\\n\\r\"; // el factor 2 agrega 2 espacio al inicio de cada elemento\n //y agrega tambien una linea lo cual es interesante para la legibilidad del formato y para que los clientes SFTP puedan\n //leer bien el archivo, como es el caso de Mobaxterm.\n\n return ([{ payload: { pantalla: \"menu-principal\" } }, msg, null])\n}\nelse if (msg.modalCallback == \"recargar\") {\n return ([null, null, null, { payload: 1 }])\n}\n\nelse if (msg.modalCallback == \"reiniciar\") {\n return ([null, null, null, null, { payload: \"sudo shutdown -r now\" }])\n}\n\nelse if (msg.modalCallback == \"apagar\") {\n return ([null, null, null, null, { payload: \"sudo poweroff\" }])\n}\n\n//============================================== FUNCIONES ==============================================================\n//esta funcion convierte un array con elementos [parametro, valor] en un objeto Json respetando los tipos de parametro (numerico, booleano, texto)\nfunction toJson(data) {\n let newJson = {}\n /*\n data.forEach(item => {\n let param = item.parametro;\n let value = item.valor;\n */\n for (let i = 0; i < data.length; i++) {\n let param = data[i].parametro;\n let value = data[i].valor;\n\n // Parseo de tipos igual que antes\n if (typeof value === 'string') {\n if (value.toLowerCase() === \"true\") {\n newJson[param] = true;\n } else if (value.toLowerCase() === \"false\") {\n newJson[param] = false;\n } else if (!isNaN(value) && value.trim() !== \"\") {\n newJson[param] = Number(value);\n } else {\n newJson[param] = value;\n }\n } else {\n // Por si el value ya viene como booleano o número real\n newJson[param] = value;\n }\n }\n return (newJson)\n}\n\n//=======================================================================================================================================\n\nfunction validarIP(ip) {\n const regex = /^(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/;\n return regex.test(ip);\n}", "outputs": 8, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 3960, + "x": 4100, "y": 2180, "wires": [ [ @@ -5165,7 +5175,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 3940, + "x": 4080, "y": 2080, "wires": [] }, @@ -5179,7 +5189,7 @@ "links": [ "b7b5cf32f7eea205" ], - "x": 4175, + "x": 4315, "y": 2200, "wires": [] }, @@ -5193,7 +5203,7 @@ "links": [ "7058b9e632aa584b" ], - "x": 4125, + "x": 4265, "y": 2120, "wires": [] }, @@ -5208,8 +5218,8 @@ "88b9b4d1c5aa7359", "ade2db3a9cf2dab1" ], - "x": 3405, - "y": 2160, + "x": 3535, + "y": 2180, "wires": [ [ "882ee24d1489b06c" @@ -5230,7 +5240,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 4160, + "x": 4300, "y": 2040, "wires": [] }, @@ -5244,7 +5254,7 @@ "links": [ "da672c95637f91bd" ], - "x": 4175, + "x": 4315, "y": 2240, "wires": [] }, @@ -5258,7 +5268,7 @@ "links": [ "cc25836d7a7314ad" ], - "x": 4175, + "x": 4315, "y": 2280, "wires": [] }, @@ -5268,14 +5278,14 @@ "z": "953e8740401d175c", "g": "e3bc37824e09b774", "name": "datos de\\n pesada y \\n snapshot", - "func": "if(msg.payload.hasOwnProperty(\"tiposDatos\")){\n return(msg)\n\n}\nelse {\n let msgmix = {}\n if (flow.get(\"snapshot_cam\") && msg.payload.hasOwnProperty(\"Picture\")) { // si recibimos snapshot extraemos informacion necesaria para mostrar en la pagina de snapshot\n msgmix.plate = msg.payload.Picture.Plate.PlateNumber // guardamos el numero de matricula\n msgmix.picture = \"data:image/png;base64,\" + msg.payload.Picture.NormalPic.Content\n msgmix.plate_time = msg.payload.Picture.SnapInfo.SnapTime\n msgmix.camera_id = msg.payload.Picture.SnapInfo.DeviceID\n }\n\n\n else if (flow.get(\"escuchar_cam\")) { // Si estamos esperando snapshots de la camara o acciones del usuario en botones left o right\n let snapshot_array = flow.get('snapshot_array') || [];\n let snapshot_readindex = flow.get('snapshot_readindex') || 0;\n let snapshot_saveindex = flow.get('snapshot_saveindex') || 0;\n let snapshot_indexmax = flow.get('snapshot_indexmax') || 0;\n\n\n if (flow.get(\"getfromarray\") == \"left\") {\n msgmix.buttons = true // indica al index.js (del uibuilder) que no tiene que inicializar la pantalla de escuchar camara\n if (snapshot_readindex > 0) {\n snapshot_readindex = snapshot_readindex - 1\n flow.set(\"snapshot_readindex\", snapshot_readindex)\n msgmix = snapshot_array[snapshot_readindex]\n msgmix.snapshot_readindex = snapshot_readindex\n msgmix.snapshot_indexmax = snapshot_indexmax\n }\n }\n else if (flow.get(\"getfromarray\") == \"right\") {\n msgmix.buttons = true // indica al index.js (del uibuilder) que no tiene que inicializar la pantalla de escuchar camara\n if (snapshot_readindex < flow.get(\"snapshot_indexmax\") - 1) {\n snapshot_readindex = snapshot_readindex + 1\n flow.set(\"snapshot_readindex\", snapshot_readindex)\n msgmix = snapshot_array[snapshot_readindex]\n msgmix.snapshot_readindex = snapshot_readindex\n msgmix.snapshot_indexmax = snapshot_indexmax\n\n }\n }\n else {\n if (msg.payload.hasOwnProperty(\"Picture\")) { // si recibimos snapshot extraemos informacion necesaria para mostrar en la pagina de escuchar camara\n msgmix.plate = msg.payload.Picture.Plate.PlateNumber // guardamos el numero de matricula\n msgmix.picture = \"data:image/png;base64,\" + msg.payload.Picture.NormalPic.Content\n msgmix.plate_time = msg.payload.Picture.SnapInfo.SnapTime\n msgmix.camera_id = msg.payload.Picture.SnapInfo.DeviceID\n msgmix.buttons = true\n\n\n snapshot_array[snapshot_saveindex] = RED.util.cloneMessage(msgmix); // Clonamos para evitar referencias\n flow.set(\"snapshot_array\", snapshot_array)\n flow.set(\"snapshot_saveindex\", snapshot_saveindex + 1)\n flow.set(\"snapshot_indexmax\", snapshot_indexmax + 1)\n\n if (snapshot_readindex == snapshot_saveindex - 1) {\n flow.set(\"snapshot_readindex\", snapshot_readindex + 1) // en caso que el index de lectura este al final, se incrementa al llegar una nueva imagen\n }\n msgmix.snapshot_indexmax = flow.get(\"snapshot_indexmax\")\n msgmix.snapshot_readindex = flow.get(\"snapshot_readindex\")\n }\n }\n }\n\n else {\n\n let msgmix = {}\n\n }\n flow.set(\"getfromarray\", \"\")\n\n //*****************************************Agrega datos de la pesada para PAGINA PRINCIPAL************************************************************ */\n if (!msg.payload.hasOwnProperty(\"Picture\")) {\n msgmix = Object.assign({}, msg, msgmix); // msg sobrescribe valores si hay conflictos\n }\n msgmix.peso = flow.get(\"peso\")\n msgmix.semaforo_color = flow.get(\"semaforo\")\n msgmix.matricula = flow.get(\"matricula\")\n msgmix.peso_estable_flag = flow.get(\"peso_estable_flag\")\n msgmix.vial = flow.get(\"numero_vial\")\n msgmix.totem_id = flow.get(\"totem_id\")\n msgmix.iplan = flow.get(\"myip\")\n msgmix.ipsupervisor = flow.get(\"websocket_url\")\n msgmix.snapshot_cam = flow.get(\"snapshot_cam\")\n msgmix.escuchar_cam = flow.get(\"escuchar_cam\")\n return msgmix;\n}", + "func": "if(msg.payload.hasOwnProperty(\"tiposDatos\")){\n return(msg)\n\n}\nelse {\n let msgmix = {}\n if (flow.get(\"snapshot_cam\") && msg.payload.hasOwnProperty(\"Picture\")) { // si recibimos snapshot extraemos informacion necesaria para mostrar en la pagina de snapshot\n msgmix.plate = msg.payload.Picture.Plate.PlateNumber // guardamos el numero de matricula\n msgmix.picture = \"data:image/png;base64,\" + msg.payload.Picture.NormalPic.Content\n msgmix.plate_time = msg.payload.Picture.SnapInfo.SnapTime\n msgmix.camera_id = msg.payload.Picture.SnapInfo.DeviceID\n }\n\n\n else if (flow.get(\"escuchar_cam\")) { // Si estamos esperando snapshots de la camara o acciones del usuario en botones left o right\n let snapshot_array = flow.get('snapshot_array') || [];\n let snapshot_readindex = flow.get('snapshot_readindex') || 0;\n let snapshot_saveindex = flow.get('snapshot_saveindex') || 0;\n let snapshot_indexmax = flow.get('snapshot_indexmax') || 0;\n\n\n if (flow.get(\"getfromarray\") == \"left\") {\n msgmix.buttons = true // indica al index.js (del uibuilder) que no tiene que inicializar la pantalla de escuchar camara\n if (snapshot_readindex > 0) {\n snapshot_readindex = snapshot_readindex - 1\n flow.set(\"snapshot_readindex\", snapshot_readindex)\n msgmix = snapshot_array[snapshot_readindex]\n msgmix.snapshot_readindex = snapshot_readindex\n msgmix.snapshot_indexmax = snapshot_indexmax\n }\n }\n else if (flow.get(\"getfromarray\") == \"right\") {\n msgmix.buttons = true // indica al index.js (del uibuilder) que no tiene que inicializar la pantalla de escuchar camara\n if (snapshot_readindex < flow.get(\"snapshot_indexmax\") - 1) {\n snapshot_readindex = snapshot_readindex + 1\n flow.set(\"snapshot_readindex\", snapshot_readindex)\n msgmix = snapshot_array[snapshot_readindex]\n msgmix.snapshot_readindex = snapshot_readindex\n msgmix.snapshot_indexmax = snapshot_indexmax\n\n }\n }\n else {\n if (msg.payload.hasOwnProperty(\"Picture\")) { // si recibimos snapshot extraemos informacion necesaria para mostrar en la pagina de escuchar camara\n msgmix.plate = msg.payload.Picture.Plate.PlateNumber // guardamos el numero de matricula\n msgmix.picture = \"data:image/png;base64,\" + msg.payload.Picture.NormalPic.Content\n msgmix.plate_time = msg.payload.Picture.SnapInfo.SnapTime\n msgmix.camera_id = msg.payload.Picture.SnapInfo.DeviceID\n msgmix.buttons = true\n\n\n snapshot_array[snapshot_saveindex] = RED.util.cloneMessage(msgmix); // Clonamos para evitar referencias\n flow.set(\"snapshot_array\", snapshot_array)\n flow.set(\"snapshot_saveindex\", snapshot_saveindex + 1)\n flow.set(\"snapshot_indexmax\", snapshot_indexmax + 1)\n\n if (snapshot_readindex == snapshot_saveindex - 1) {\n flow.set(\"snapshot_readindex\", snapshot_readindex + 1) // en caso que el index de lectura este al final, se incrementa al llegar una nueva imagen\n }\n msgmix.snapshot_indexmax = flow.get(\"snapshot_indexmax\")\n msgmix.snapshot_readindex = flow.get(\"snapshot_readindex\")\n }\n }\n }\n\n else {\n\n let msgmix = {}\n\n }\n flow.set(\"getfromarray\", \"\")\n\n //*****************************************Agrega datos de la pesada para PAGINA PRINCIPAL************************************************************ */\n if (!msg.payload.hasOwnProperty(\"Picture\")) {\n msgmix = Object.assign({}, msg, msgmix); // msg sobrescribe valores si hay conflictos\n }\n msgmix.peso = flow.get(\"peso\")\n msgmix.semaforo_color = flow.get(\"semaforo\")\n msgmix.matricula = flow.get(\"matricula\")\n msgmix.peso_estable_flag = flow.get(\"peso_estable_flag\")\n msgmix.vial = flow.get(\"numero_vial\")\n msgmix.totem_id = flow.get(\"totem_id\")\n msgmix.iplan = flow.get(\"myip\")\n msgmix.ipsupervisor = flow.get(\"websocket_url\")\n msgmix.snapshot_cam = flow.get(\"snapshot_cam\")\n msgmix.escuchar_cam = flow.get(\"escuchar_cam\")\n msgmix.distance = flow.get(\"distance\") // Añadido por david\n msgmix.distance_min = flow.get(\"distance_min\") // Añadido por david\n return msgmix;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 3520, + "x": 3660, "y": 2200, "wires": [ [ @@ -5293,8 +5303,8 @@ "links": [ "b890981ca603e6e1" ], - "x": 3405, - "y": 2260, + "x": 3535, + "y": 2240, "wires": [ [ "882ee24d1489b06c" @@ -5315,7 +5325,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 3740, + "x": 3880, "y": 2100, "wires": [] }, @@ -5329,7 +5339,7 @@ "links": [ "108fa8de0b9851c3" ], - "x": 4175, + "x": 4315, "y": 2320, "wires": [] }, @@ -5347,7 +5357,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 4220, + "x": 4360, "y": 2360, "wires": [] }, @@ -5358,7 +5368,7 @@ "g": "e3bc37824e09b774", "name": "CONFIGURACION DE PARAMETROS Y PRUEBAS ", "info": "Este grupo de nodos permiten servir una pagina web para que el usuario desde un movil pueda realizar la gestion de configuracion\nde los principales parametros del Totem asi como realizar algunas pruebas en la camara y en el semaforo.\nEl punto central de este grupo es el paquete UIBUILDER para nodered el cual convive sin inconvenientes con el DASHBOARD de nodered.\nEl uibuilder posee un nodo para cada path de acceso que deseemos habilitar. Cada nodo es independiente del otro en el sentido que \ncada uno dispone de un index.html, un index.js y un index.css ue permiten configurar la pagina que sirve el nodo. \nRecordemos que estos archivos se ejecutan en el cliente, por lo tanto para que el index.js tenga acceso a los datos de nodered y nodered \na los datos generados por el cliente, el nodo uibuilder establece una comunicacion websocket transparente para el usuario de manera\na poder intercambiar informacion entre nodered y el browser. Los elementos fundamentales en index.js para llevar a cabo esta comunicacion\nson las funciones \"uibuilder.onChange()\" para recibir los mensajes de nodered y \"uibuilder.send()\" para enviar a nodered los datos generados \npor el cliente.\nEl nodo \"buttons decoder\" fundamentalmente se dedica a interpretar los comandos del cliente (botones que ha pulsado el usuario) de manera a recopilar\nla informacion adecuada para enviar al uibuilder nuevamente de manera que cambie de pagina o muestre ciertos datos, o tambien a ejecutar\nlos comandos solicitados como reboot, apagar dispositivo, encender / apagar semaforo, ...\nEl nodo de entrada \"datos de pesada y snapshot\" recibe por un lado los snapshots enviados por la camara y extrae la informacion necesaria \npara enviar al cliente, y por otro lado siempre que haya alguna recepcion de datos del Totem se preparan los datos correspondientes para \ncolocarlos en la pantalla principal del uibuilder o pantalla de monitoreo.", - "x": 3650, + "x": 3730, "y": 2340, "wires": [] }, @@ -5372,7 +5382,7 @@ "links": [ "6f9cc9fc71e8ca71" ], - "x": 4175, + "x": 4315, "y": 2400, "wires": [] }, @@ -5390,7 +5400,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 4220, + "x": 4360, "y": 2440, "wires": [] }, @@ -5398,6 +5408,7 @@ "id": "1826a83d58a7539b", "type": "uibuilder", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "", "topic": "", @@ -5432,6 +5443,7 @@ "id": "51e2882d2082cd6c", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "debug 8", "active": true, @@ -5450,6 +5462,7 @@ "id": "153ff925612f0a72", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "", "props": [ @@ -5496,6 +5509,7 @@ "id": "4be318029a87b632", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "", "props": [ @@ -5547,6 +5561,7 @@ "id": "42a05ba042772cf0", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "", "props": [ @@ -5588,6 +5603,7 @@ "id": "3a6c2ab4113cbfc9", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "", "props": [ @@ -5629,6 +5645,7 @@ "id": "656a6ccd2e2d8874", "type": "link in", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "uibuilder-in", "links": [ @@ -5646,6 +5663,7 @@ "id": "9334d6e746bacf1d", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "response", "func": "if ((msg.payload.boton == \"ok\") && flow.get(\"supervisor\")){\n let msg_out = {}\n msg_out.payload = { numero_vial: flow.get(\"numero_vial\"), totem_id: flow.get(\"totem_id\"), validacion: \"ok\" }\n node.send([msg_out, null])\n}\nreturn;", @@ -5668,6 +5686,7 @@ "id": "a1f46ee9a5bf3bd0", "type": "link out", "z": "953e8740401d175c", + "d": true, "g": "427191a7a5984434", "name": "link out 8", "mode": "link", @@ -5702,7 +5721,7 @@ "payload": "946DA2A4-B07B-482D-A98F-C6EB0FFABCAE", "payloadType": "str", "x": 2700, - "y": 1880, + "y": 2000, "wires": [ [ "120a33aec5cdad35" @@ -5723,7 +5742,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 4280, + "x": 4420, "y": 2240, "wires": [] }, @@ -5739,7 +5758,7 @@ "createDir": true, "overwriteFile": "true", "encoding": "none", - "x": 4260, + "x": 4400, "y": 2160, "wires": [ [] @@ -5793,7 +5812,7 @@ "type": "debug", "z": "953e8740401d175c", "name": "debug 29", - "active": true, + "active": false, "tosidebar": true, "console": false, "tostatus": false, @@ -5891,8 +5910,8 @@ "id": "53335688d117ec96", "type": "comment", "z": "953e8740401d175c", - "name": "Version 1.3.1 de bascula autonoma", - "info": "**Version 1.3.1** \n- Hemos puesto el flag flow.set(\"RFID_ok_flag\", false) cuando leemos un QR y flow.set(\"QR_ok_flag\", false) cuando leemos una tarjeta, esto permite\nque se utilice un QR aunque primero hayamos metido una tarjeta invalida y viceversa. Se hizo en el nodo \"envio QR/RFID\".\n**Version 1.3** \n- En esta version hemos cambiado los timers a modo contexto local (del nodo) Importante este punto ya que el timer es un objeto no serializable\ny por lo tanto no deberiamos guardar en contexto flow o global ya que esos contextos estan previstos para objetos serializables (estados, valores, arrays, json...)\nSi lo ponemos en flow el timer puede romperse, quedar corrupto, o incoherente al hacer deploy o cualquier operacion de inicio.\nlo limpio es hacerlo en el contexto del nodo y poner el cierre del timer al salir del nodo en node.on(\"close\"). En su lugar ponemos el codigo\nen la pestaña del editor del nodo \"Al final\" que es lo mismo. La pestaña Close se refiere a cuando el nodered se reinicia, se hace redeploy etc..\n- Hemos cambiado los timers del snapshot en Analisis detector y Analisis de peso, igualmente hemos cambiado la forma de apagarlo desde otro nodo.\nPara ello hemos implementado en el nodo donde reside el timer un codigo que se activa cuando topic = cancel_snapshot_timer.\n - Se arreglo la repeticion del mensaje (audio) de firme en la pantalla. Para ello hemos inluido el flag de solicitud de firma en el \"if\" de envio del mensaje\n de manera que si ya se hizo solicitud de la firma no se aplica el mensaje nuevamente.\n- Hemos puesto un nuevo nodo (esperar) en el grupo deteccion de matricula para evitar un posible aunque remoto caso cuando se activa el detector remoto pero no se activa la bascula\ndurante unos segundos. La descripcion esta en un nodo comentario \"CASO QUE PODRIA BLOQUEAR EL SISTEMA\" que se encuentra en el grupo \"ITSAPI - WEB SERVER Y ANALISIS\".\n\n**Version 1.2** Hemos agregado una nueva funcionalidad para indicarle al conductor acerca de la ubicacion interna donde debe dirigirse con el residuo que\ntransporta. Esta notificacion se muestra una vez que hayan cumplido todos los requisitos de entrada y antes de poner el semaforo en verde. \nPara esta funcionalidad hemos introducido un codigo en el nodo \"Analisis del modo de Operacion\" (lineas 76 a 112) y en el nodo \"check json content\"\nen las lineas 44 a 50 bajo el titulo \"RESPUESTA DE LA REVISION DE LA UBICACION INTERNA EN BD\". Si recibimos respuesta positiva de la BD es decir que si \ntiene ubicacion interna el residuo presentado entonces sacamos notificacion con lo que dice el campo de descripcion encontrado en la tabla, en caso contrario\nel mensaje que aparece en pantalla es diciendo que no hay ubicacion para ese residuo.\nSe ha hecho una modificacion en el nodo \"detector rx\" para inicializar todas las variables del Totem cuando ocurra una falsa deteccion de vehiculo, es decir \ncuando que se recibe la señal de detector remoto ON pero no se activa la bascula en el tiempo previsto. Dado que en ese momento hay variables que han cambiado de estado \ny ademas se ha recibido una imagen, es necesario forzar la inicializacion de todas las variables ya que el peso no se ha movido de cero. Si dejamos las variables\nsin inicializar, cuando un vehiculo entre es probable que haya estados confusos.\n\n**Version 1.12** Se corrigio el nodo peso estable para procesar correctamente el valor de Peso Maximo Admitido y sacar un mensaje que no se pueda borrar\nhasta que el vehiculo abandone la bascula. Se agrego un nodo para mantener el aviso de salir de la bascula en caso de PMA, si el usuario pulsa OK.\nCorregido en el nodo \"check JSON content\" la recepcion de la matricula asociada a una tarjeta. Hemos activado los flags correspondientes para que el nodo \n\"matricula 2\" pueda hacer el chequeo de la matricula respecto a si esta o no en transito. \nEn el nodo \"Analisis del modo de operacion\" hemos puesto una condicion para no mostrar el boton de salida cuando el usuario utiliza una tarjerta valida.\nEn el nodo \"Analisis del modo de operacion\" hemos colocado una condicion para sacar la pantalla de firma. Esta condicion es que se trate de que estamos en \nel proceso de movimiento inicial. Adicionalmente si estamos en el proceso de movimiento final y la firma es obligatoria, marcamos el flag de firma como si estuviera\nrealizada ya que para la salida no es preciso firmar.\nEn el archivo generado de la firma se elimino el encabezado \"data:image/png Base64,\" Esto lo hacemos en el nodo firma en la linea 252 del script.\ndataUrl = canvas.toDataURL().split(\",\")[1];\n\n**Version 1.11**Se puso una condicion (peso en bascula > pmin) en el nodo \"enviar matricula\" para enviar matricula al nodo de analisis. Esto evita que se este\nenviando matricula si se recibe sin que haya vehiculo en bascula. Esto no evita que se reciban matriculas automaticas antes de entrar el vehiculo en la bascula.\nEstas ultimas fotos se conservan en memoria hasta que el vehiculo entre en la bascula y pueden ser utilizadas como foto principal en caso de fallo en la solicitud.\nHemos eliminado en la linea 156 del nodo matricula2 la condicion de \"qr_revisado\" para eximirlo de disponer de matricula debido a que ahora el codigo qr puede estar asociado a varias matriculas.\ny por lo tanto sera necesario disponer de una matricula a pesar de tener el codigo de autorizacio (solo indica residuo).\nHemos inicializado la matricula [flow.set(\"matricula\", \"Sin Matricula\")] tambien en el momento en que el peso supera a pmin por primera vez (es decir entrando en la bascula).\nSe agrego en la salida de la edicion de matricula [flow.set(\"matriculacheck_solicitada\", false)] para permitir que se busque nuevamente la matricula en BD.\n\n**Version 1.1** Hemos agregado excepcion de obligacion de tener que disponer de matricula para el caso de presentar una tarjeta RFID. Anteriormente se habia puesto en el nodo de \"Analisis\ndel modo de operacion\" (*let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || true // siempre es obligatoria*) una linea para obligar a tener siempre matricula,\nindependiente de lo que este configurado en el archivo de configuracion. Ahora esa linea sigue funcionando pero en el caso de la tarjeta se permite que no haya matricula ya que esta identificacion \ncontiene la matricula unica. Ver linea 53 en el nodo mencionado anteriormente. No es el caso de los QR los cuales puede haber el mismo GUUID asociados a diferentes matriculas.\n\nSe han agregado nos nuevos campos a la tabla movimierntos_cerrados en el supervisor estos campos son \"qr_salida\" y \"rfid_salida\". La presencia de estos \ndos campos es para disponer de la identificaciob utilizada en salida en caso de hacerlo. Para ello en el nodo \"Analisis del modo de Operacion\" se evalua \nsi estamos en el movimiento inicial o final para ver cual campo es el que tenemos que rellenar. Est se hace el la linea nº 100\nSe ha moviso la inicializacion flow.set(\"distance_flag_SET\", false) al momento donde la bascula pasa de peso < pmin por primera vez. \nAntes se inicializaba cada vez que el peso que llegaba era menor que pmin. Esto podia ocasionar un error ya que el nodo detector perdia el control\nde este flag al ser inicializado cada vez que el peso < pmin.\n\nEl nodo \"matricula 2\" sustituye al nodo matricula anterior. Este nuevo contiene todas las modificaciones necesarias para adaptarse a los \nnuevos requerimientos de la bascula automatica\n\nPara que el QR pueda entrar en la planta es necesario que la matricula este disponible.\nEn caso de que la matricula leida sea diferente a la matricula obtenida en la BD luego de enviar el QR se toma la matricula leida de la BD\n\n**version 1.0.** Este codigo de Bascula Autonoma sale a partir del Totem Autonomo. Todo el codigo relativo a la gestion de BAse de Datos se traslada al RPI Supervisor\nEn este RPi solo queda lo relativo a la gestion de sensores, camaras, lectores de Identioficacion, semaforo, barrera y la pantalla para que el usuario \npueda interactuar con el sistema como por ejemplo hacer seleccion del residuo a traves de un menu de seleccion.\n\nEn esta version se ha introducido el termino PMA(Peso Maximo Autorizado. Este es un valor que el Totem recibe cuando el Supervisor le envia la autorizacion\nde la matricula junto con la tara- El Totem revisa el peso estable del vehiculo con el PMA recibidoy en caso de ser superior se envia un aviso en la pantalla\nindicandole al conductor que debe retroceder ya que supera el peso admitido.\n\nOtra función que contiene esta version es el chequeo de la Tara. Si el valor recibido de la Tara es superior a cero entonces el movimiento inicial recinbido por el supervisor \nes enviado como movimiento cerrado al Servidor.Realmente para el Totem es transparente. La gestion de la Tara en efecto la hace el Supervisor una vez que recibe\nel movimiento inicial que envia el Totem.", + "name": "Version 1.3.2 de bascula autonoma", + "info": "**Version 1.3.2** \n- Hemos colocado un codigo de dos lineas para eliminar el boton del menu activo \"COMPLETAR INFO\" en caso que se presente una tarjeta o un codigo QR. \nEsto lo hicimos en el nodo \"Analisis del modo de Operacion\" en la linea 70 donde chequeamos si estamos en movimiento inicial.\n\n- Corregido un \"error\" que no permitia cerrar el movimiento inicial cuando se pasaba una tarjeta si teniamos el menu activo y la firma obligatoria. \nSe agrego una condicion (\"ID_verificado\") en la condicion global para llamar a la firma. Esto es en el nodo \"Analisis de Operacion\" en las primeras lineas\nif (flow.get(\"firma_obligatoria\") && !flow.get(\"firma_flag\") && !flow.get(\"firma_ok_flag\") && !flow.get(\"supervisor\") && (!flow.get(\"menu_activo\") || (flow.get(\"menu_activo\") && (flow.get(\"menu_seleccionado_flag\") || ID_verificado)))) \nCon esto permite continuar con la firma en caso que tengamos menu_activo y firma obligatoria y entremos con tarjeta o con codigo QR.\n\n**Version 1.3.1**\n- Hemos colocado una opcion mas en el menu de configuración en \"Pruebas del Sistema\" -> \"Probar Sensor\". Esto permite visualizar la salida del valor\nde la distancia que esta midiendo el sensor cada segundo. Para que el medidor no este continuamente inundando el configurador con el dato de distancia\nhemos colocado un switch el cual solo deja pasar ese dato cuando se activa el menu, lo inhabilita cuando se sale del menu.\n\n- Hemos puesto el flag flow.set(\"RFID_ok_flag\", false) cuando leemos un QR y flow.set(\"QR_ok_flag\", false) cuando leemos una tarjeta, esto permite\nque se utilice un QR aunque primero hayamos metido una tarjeta invalida y viceversa. Se hizo en el nodo \"envio QR/RFID\".\n\n**Version 1.3** \n- En esta version hemos cambiado los timers a modo contexto local (del nodo) Importante este punto ya que el timer es un objeto no serializable\ny por lo tanto no deberiamos guardar en contexto flow o global ya que esos contextos estan previstos para objetos serializables (estados, valores, arrays, json...)\nSi lo ponemos en flow el timer puede romperse, quedar corrupto, o incoherente al hacer deploy o cualquier operacion de inicio.\nlo limpio es hacerlo en el contexto del nodo y poner el cierre del timer al salir del nodo en node.on(\"close\"). En su lugar ponemos el codigo\nen la pestaña del editor del nodo \"Al final\" que es lo mismo. La pestaña Close se refiere a cuando el nodered se reinicia, se hace redeploy etc..\n\n- Hemos cambiado los timers del snapshot en Analisis detector y Analisis de peso, igualmente hemos cambiado la forma de apagarlo desde otro nodo.\nPara ello hemos implementado en el nodo donde reside el timer un codigo que se activa cuando topic = cancel_snapshot_timer.\n\n- Se arreglo la repeticion del mensaje (audio) de firme en la pantalla. Para ello hemos inluido el flag de solicitud de firma en el \"if\" de envio del mensaje\n de manera que si ya se hizo solicitud de la firma no se aplica el mensaje nuevamente.\n\n- Hemos puesto un nuevo nodo (esperar) en el grupo deteccion de matricula para evitar un posible aunque remoto caso cuando se activa el detector remoto pero no se activa la bascula\ndurante unos segundos. La descripcion esta en un nodo comentario \"CASO QUE PODRIA BLOQUEAR EL SISTEMA\" que se encuentra en el grupo \"ITSAPI - WEB SERVER Y ANALISIS\".\n\n**Version 1.2** Hemos agregado una nueva funcionalidad para indicarle al conductor acerca de la ubicacion interna donde debe dirigirse con el residuo que\ntransporta. Esta notificacion se muestra una vez que hayan cumplido todos los requisitos de entrada y antes de poner el semaforo en verde. \nPara esta funcionalidad hemos introducido un codigo en el nodo \"Analisis del modo de Operacion\" (lineas 76 a 112) y en el nodo \"check json content\"\nen las lineas 44 a 50 bajo el titulo \"RESPUESTA DE LA REVISION DE LA UBICACION INTERNA EN BD\". Si recibimos respuesta positiva de la BD es decir que si \ntiene ubicacion interna el residuo presentado entonces sacamos notificacion con lo que dice el campo de descripcion encontrado en la tabla, en caso contrario\nel mensaje que aparece en pantalla es diciendo que no hay ubicacion para ese residuo.\nSe ha hecho una modificacion en el nodo \"detector rx\" para inicializar todas las variables del Totem cuando ocurra una falsa deteccion de vehiculo, es decir \ncuando que se recibe la señal de detector remoto ON pero no se activa la bascula en el tiempo previsto. Dado que en ese momento hay variables que han cambiado de estado \ny ademas se ha recibido una imagen, es necesario forzar la inicializacion de todas las variables ya que el peso no se ha movido de cero. Si dejamos las variables\nsin inicializar, cuando un vehiculo entre es probable que haya estados confusos.\n\n**Version 1.12** Se corrigio el nodo peso estable para procesar correctamente el valor de Peso Maximo Admitido y sacar un mensaje que no se pueda borrar\nhasta que el vehiculo abandone la bascula. Se agrego un nodo para mantener el aviso de salir de la bascula en caso de PMA, si el usuario pulsa OK.\nCorregido en el nodo \"check JSON content\" la recepcion de la matricula asociada a una tarjeta. Hemos activado los flags correspondientes para que el nodo \n\"matricula 2\" pueda hacer el chequeo de la matricula respecto a si esta o no en transito. \nEn el nodo \"Analisis del modo de operacion\" hemos puesto una condicion para no mostrar el boton de salida cuando el usuario utiliza una tarjerta valida.\nEn el nodo \"Analisis del modo de operacion\" hemos colocado una condicion para sacar la pantalla de firma. Esta condicion es que se trate de que estamos en \nel proceso de movimiento inicial. Adicionalmente si estamos en el proceso de movimiento final y la firma es obligatoria, marcamos el flag de firma como si estuviera\nrealizada ya que para la salida no es preciso firmar.\nEn el archivo generado de la firma se elimino el encabezado \"data:image/png Base64,\" Esto lo hacemos en el nodo firma en la linea 252 del script.\ndataUrl = canvas.toDataURL().split(\",\")[1];\n\n**Version 1.11**Se puso una condicion (peso en bascula > pmin) en el nodo \"enviar matricula\" para enviar matricula al nodo de analisis. Esto evita que se este\nenviando matricula si se recibe sin que haya vehiculo en bascula. Esto no evita que se reciban matriculas automaticas antes de entrar el vehiculo en la bascula.\nEstas ultimas fotos se conservan en memoria hasta que el vehiculo entre en la bascula y pueden ser utilizadas como foto principal en caso de fallo en la solicitud.\nHemos eliminado en la linea 156 del nodo matricula2 la condicion de \"qr_revisado\" para eximirlo de disponer de matricula debido a que ahora el codigo qr puede estar asociado a varias matriculas.\ny por lo tanto sera necesario disponer de una matricula a pesar de tener el codigo de autorizacio (solo indica residuo).\nHemos inicializado la matricula [flow.set(\"matricula\", \"Sin Matricula\")] tambien en el momento en que el peso supera a pmin por primera vez (es decir entrando en la bascula).\nSe agrego en la salida de la edicion de matricula [flow.set(\"matriculacheck_solicitada\", false)] para permitir que se busque nuevamente la matricula en BD.\n\n**Version 1.1** Hemos agregado excepcion de obligacion de tener que disponer de matricula para el caso de presentar una tarjeta RFID. Anteriormente se habia puesto en el nodo de \"Analisis\ndel modo de operacion\" (*let matricula_obligatoria = flow.get(\"matricula_obligatoria\") || true // siempre es obligatoria*) una linea para obligar a tener siempre matricula,\nindependiente de lo que este configurado en el archivo de configuracion. Ahora esa linea sigue funcionando pero en el caso de la tarjeta se permite que no haya matricula ya que esta identificacion \ncontiene la matricula unica. Ver linea 53 en el nodo mencionado anteriormente. No es el caso de los QR los cuales puede haber el mismo GUUID asociados a diferentes matriculas.\n\nSe han agregado nos nuevos campos a la tabla movimierntos_cerrados en el supervisor estos campos son \"qr_salida\" y \"rfid_salida\". La presencia de estos \ndos campos es para disponer de la identificaciob utilizada en salida en caso de hacerlo. Para ello en el nodo \"Analisis del modo de Operacion\" se evalua \nsi estamos en el movimiento inicial o final para ver cual campo es el que tenemos que rellenar. Est se hace el la linea nº 100\nSe ha moviso la inicializacion flow.set(\"distance_flag_SET\", false) al momento donde la bascula pasa de peso < pmin por primera vez. \nAntes se inicializaba cada vez que el peso que llegaba era menor que pmin. Esto podia ocasionar un error ya que el nodo detector perdia el control\nde este flag al ser inicializado cada vez que el peso < pmin.\n\nEl nodo \"matricula 2\" sustituye al nodo matricula anterior. Este nuevo contiene todas las modificaciones necesarias para adaptarse a los \nnuevos requerimientos de la bascula automatica\n\nPara que el QR pueda entrar en la planta es necesario que la matricula este disponible.\nEn caso de que la matricula leida sea diferente a la matricula obtenida en la BD luego de enviar el QR se toma la matricula leida de la BD\n\n**version 1.0.** Este codigo de Bascula Autonoma sale a partir del Totem Autonomo. Todo el codigo relativo a la gestion de BAse de Datos se traslada al RPI Supervisor\nEn este RPi solo queda lo relativo a la gestion de sensores, camaras, lectores de Identioficacion, semaforo, barrera y la pantalla para que el usuario \npueda interactuar con el sistema como por ejemplo hacer seleccion del residuo a traves de un menu de seleccion.\n\nEn esta version se ha introducido el termino PMA(Peso Maximo Autorizado. Este es un valor que el Totem recibe cuando el Supervisor le envia la autorizacion\nde la matricula junto con la tara- El Totem revisa el peso estable del vehiculo con el PMA recibidoy en caso de ser superior se envia un aviso en la pantalla\nindicandole al conductor que debe retroceder ya que supera el peso admitido.\n\nOtra función que contiene esta version es el chequeo de la Tara. Si el valor recibido de la Tara es superior a cero entonces el movimiento inicial recibido por el supervisor \nes enviado como movimiento cerrado al Servidor.Realmente para el Totem es transparente. La gestion de la Tara en efecto la hace el Supervisor una vez que recibe\nel movimiento inicial que envia el Totem.", "x": 1300, "y": 800, "wires": [] @@ -6060,6 +6079,7 @@ "id": "42499939644932e1", "type": "link out", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "link out 1", "mode": "link", @@ -6074,6 +6094,7 @@ "id": "e7cb71b1e09afda6", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "function 2", "func": "if ((msg.payload.totem_id == \"totem_1\" || msg.payload.totem_id == \"*\") && msg.payload.numero_vial == 3) { // verifica que los datos son para este totem\n node.send([msg, null])\n\n}\nelse if ((msg.payload.totem_id == \"totem_2\" || msg.payload.totem_id == \"*\") && msg.payload.numero_vial == 4) { // verifica que los datos son para este totem\n node.send([null, msg])\n}\nelse if ((msg.payload.totem_id == \"totem_1\" || msg.payload.totem_id == \"*\") && msg.payload.numero_vial == 2) { // verifica que los datos son para este totem\n node.send([null, null, msg])\n}\nelse if ((msg.payload.totem_id == \"totem_2\" || msg.payload.totem_id == \"*\") && msg.payload.numero_vial == 5) { // verifica que los datos son para este totem\n node.send([null, null, null, msg])\n}\nreturn", @@ -6104,6 +6125,7 @@ "id": "d117899cc8faa6d0", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "debug 5", "active": true, @@ -6122,6 +6144,7 @@ "id": "27ff2fd5838987df", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "debug 6", "active": true, @@ -6140,6 +6163,7 @@ "id": "5bf3c0851a93230d", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": " vial 3 totem 1", "func": "msg.payload = { \"numero_vial\": 3, \"totem_id\": \"totem_1\", \"device\": \"supervisor\", \"matricula\": \"0236MWK\", \"accion\": \"check\" }\n\nreturn msg;", @@ -6161,6 +6185,7 @@ "id": "cb449de1338a8b6b", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "vial 4 totem 2", "func": "msg.payload = { \"numero_vial\": 4, \"totem_id\": \"totem_2\", \"device\": \"supervisor\", \"matricula\": \"0312MGB\", \"accion\": \"check\" }\n\nreturn msg;", @@ -6182,6 +6207,7 @@ "id": "545d688854bdc270", "type": "delay", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "", "pauseType": "delay", @@ -6210,6 +6236,7 @@ "id": "6bdb05cfc53c7c6f", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "", "props": [ @@ -6241,6 +6268,7 @@ "id": "c405dbca2e94854c", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "vial 2 totem 1", "func": "msg.payload = { \"numero_vial\": 2, \"totem_id\": \"totem_1\", \"device\": \"supervisor\", \"matricula\": \"0420MMR\", \"accion\": \"check\" }\n\nreturn msg;", @@ -6263,6 +6291,7 @@ "id": "c5c336e381de6e5d", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "debug 7", "active": true, @@ -6281,6 +6310,7 @@ "id": "35c3f5c0d362ff4d", "type": "function", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "vial 5 totem 2", "func": "msg.payload = { \"numero_vial\": 5, \"totem_id\": \"totem_2\", \"device\": \"supervisor\", \"matricula\": \"0397FHJ\", \"accion\": \"check\" }\n\nreturn msg;", @@ -6302,6 +6332,7 @@ "id": "10b95a9046bf57f7", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "debug 9", "active": true, @@ -6349,6 +6380,7 @@ "id": "1b2a16010cfceb38", "type": "debug", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "debug 15", "active": true, @@ -6367,6 +6399,7 @@ "id": "84f8ce2853a75080", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "c0824ad89a3b525c", "name": "", "props": [ @@ -6521,72 +6554,6 @@ "y": 1500, "wires": [] }, - { - "id": "ab6a1ac9a828933e", - "type": "function", - "z": "953e8740401d175c", - "name": "function 3", - "func": "\nnode.warn(\"LATIDO \" + new Date().toISOString());\nreturn msg;", - "outputs": 1, - "timeout": 0, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 4540, - "y": 1900, - "wires": [ - [ - "d345adcc7adb9b9b" - ] - ] - }, - { - "id": "d345adcc7adb9b9b", - "type": "debug", - "z": "953e8740401d175c", - "name": "debug 23", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 4720, - "y": 1900, - "wires": [] - }, - { - "id": "0378140a81ca2122", - "type": "inject", - "z": "953e8740401d175c", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "1", - "payloadType": "num", - "x": 4350, - "y": 1900, - "wires": [ - [ - "ab6a1ac9a828933e" - ] - ] - }, { "id": "0dbd268561a07c9e", "type": "catch", @@ -6629,7 +6596,7 @@ "z": "953e8740401d175c", "g": "0e2b148022a7af13", "name": "espera ", - "func": " /* OJO Aqui utilizamos un timer setInterval que guardamos en el contexto local. Importante este punto ya que el timer es un objeto no serializable\n y por lo tanto no deberiamos guardar en contexto flow o global ya que esos contextos estan previstos para objetos serializables (estados, valores, arrays, json...)\n Si lo ponemos en flow el timer puede romperse, quedar corrupto, o incoherente al hacer deploy o cualquier operacion de inicio.\n lo limpio es hacerlo en el contexto del nodo y poner el cierre del timer al salir del nodo en node.on(\"close\"). En su lugar ponemos el codigo\n en la pestaña \"Al final\" que es lo mismo. Close se refiere a cuando el node se reinicia, se hace redeploy etc..\n*/\n\nif (!flow.get(\"peso_bajo_flag\") && !flow.get(\"order_sent\") ) { // si hay peso en bascula y el mensaje no ha sido enviado a proximo nodo lo enviamos ahora \n node.send({ payload: 1 });\n flow.set(\"order_sent\", true)\n node.status({ fill: \"green\", shape: \"dot\", text: \"sin delay...\" });\n}\nelse{// \n if (!flow.get(\"interval_running\") && !flow.get(\"order_sent\")) { // si el timer no ha sido arrancado y no hemos enviado mensaje\n node.status({ fill: \"yellow\", shape: \"dot\", text: \"esperando 'peso_bajo_flag'=false \" });\n flow.set(\"interval_running\", true) // marcamos timer corriendo\n let t = context.get(\"interval_matricula\"); // En la primera vez es undefined pero funciona correctamente al hacer t = setInterval mas adelante\n if (t) clearInterval(t);\n\n context.set(\"counter_espera_peso\", 0);\n let c = context.get(\"counter_espera_peso\") || 0;\n\n t = setInterval(() => {\n c = (context.get(\"counter_espera_peso\") || 0) + 1;\n context.set(\"counter_espera_peso\", c);\n\n //node.warn(\"contador = \" + c);\n\n if (c >= 40) {\n clearInterval(t);\n context.set(\"interval_matricula\", null);\n node.status({ fill: \"red\", shape: \"dot\", text: \"terminado ciclo de espera\" });\n flow.set(\"interval_running\", false);\n return;\n }\n\n if (!flow.get(\"peso_bajo_flag\") && !flow.get(\"peso_bajo_flag_forzado\")) {\n clearInterval(t);\n context.set(\"interval_matricula\", null);\n node.status({ fill: \"green\", shape: \"dot\", text: \"liberado (peso_bajo_flag=false)\" });\n flow.set(\"interval_running\", false);\n flow.set(\"order_sent\", true);\n node.send([{ payload: 1 }, null]);\n return;\n }\n }, 400);\n\n context.set(\"interval_matricula\", t);\n }\n}\n\nreturn;", + "func": " /* OJO Aqui utilizamos un timer setInterval que guardamos en el contexto local. Importante este punto ya que el timer es un objeto no serializable\n y por lo tanto no deberiamos guardar en contexto flow o global ya que esos contextos estan previstos para objetos serializables (estados, valores, arrays, json...)\n Si lo ponemos en flow el timer puede romperse, quedar corrupto, o incoherente al hacer deploy o cualquier operacion de inicio.\n lo limpio es hacerlo en el contexto del nodo y poner el cierre del timer al salir del nodo en node.on(\"close\"). En su lugar ponemos el codigo\n en la pestaña \"Al final\" que es lo mismo. Close se refiere a cuando el node se reinicia, se hace redeploy etc..\n*/\n\nif (!flow.get(\"peso_bajo_flag\") && !flow.get(\"order_sent\") ) { // si hay peso en bascula y el mensaje no ha sido enviado a proximo nodo lo enviamos ahora \n node.send({ payload: 1 });// Este es el mensaje que enviamos al proximo nodo para que realice el procesamiento de la matricula\n flow.set(\"order_sent\", true)\n node.status({ fill: \"green\", shape: \"dot\", text: \"sin delay...\" });\n}\nelse{// \n if (!flow.get(\"interval_running\") && !flow.get(\"order_sent\")) { // si el timer no ha sido arrancado y no hemos enviado mensaje\n node.status({ fill: \"yellow\", shape: \"dot\", text: \"esperando 'peso_bajo_flag'=false \" });\n flow.set(\"interval_running\", true) // marcamos timer corriendo\n let t = context.get(\"interval_matricula\"); // En la primera vez es undefined pero funciona correctamente al hacer t = setInterval mas adelante\n if (t) clearInterval(t);\n\n context.set(\"counter_espera_peso\", 0);\n let c = context.get(\"counter_espera_peso\") || 0;\n\n t = setInterval(() => {\n c = (context.get(\"counter_espera_peso\") || 0) + 1;\n context.set(\"counter_espera_peso\", c);\n\n //node.warn(\"contador = \" + c);\n\n if (c >= 40) {\n clearInterval(t);\n context.set(\"interval_matricula\", null);\n node.status({ fill: \"red\", shape: \"dot\", text: \"terminado ciclo de espera\" });\n flow.set(\"interval_running\", false);\n return;\n }\n\n if (!flow.get(\"peso_bajo_flag\") && !flow.get(\"peso_bajo_flag_forzado\")) {\n clearInterval(t);\n context.set(\"interval_matricula\", null);\n node.status({ fill: \"green\", shape: \"dot\", text: \"liberado (peso_bajo_flag=false)\" });\n flow.set(\"interval_running\", false);\n flow.set(\"order_sent\", true);\n node.send([{ payload: 1 }, null]);\n return;\n }\n }, 400);\n\n context.set(\"interval_matricula\", t);\n }\n}\n\nreturn;", "outputs": 1, "timeout": 0, "noerr": 0, @@ -6992,5 +6959,120 @@ "a395ed21d7049d5d" ] ] + }, + { + "id": "8ccf22739ca72997", + "type": "switch", + "z": "953e8740401d175c", + "g": "e3bc37824e09b774", + "name": "detector", + "property": "display_detector", + "propertyType": "flow", + "rules": [ + { + "t": "true" + } + ], + "checkall": "true", + "repair": false, + "outputs": 1, + "x": 3500, + "y": 2120, + "wires": [ + [ + "882ee24d1489b06c" + ] + ] + }, + { + "id": "7fd2f6e6fe3f37ea", + "type": "link in", + "z": "953e8740401d175c", + "g": "e3bc37824e09b774", + "name": "link in 1", + "links": [ + "f730c0726e257f7f" + ], + "x": 3405, + "y": 2120, + "wires": [ + [ + "8ccf22739ca72997" + ] + ] + }, + { + "id": "8bfc0e03b763b6b1", + "type": "inject", + "z": "953e8740401d175c", + "g": "05cb4985c3c68ae8", + "name": "peso 1500", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"totem_id\":\"totem_1\",\"numero_vial\":2,\"peso\":1500}", + "payloadType": "json", + "x": 2860, + "y": 1620, + "wires": [ + [ + "41b4309de63a6bba" + ] + ] + }, + { + "id": "eb6a49472973163d", + "type": "inject", + "z": "953e8740401d175c", + "g": "05cb4985c3c68ae8", + "name": "peso 0", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"totem_id\":\"totem_1\",\"numero_vial\":2,\"peso\":0}", + "payloadType": "json", + "x": 2850, + "y": 1680, + "wires": [ + [ + "41b4309de63a6bba" + ] + ] + }, + { + "id": "41b4309de63a6bba", + "type": "link out", + "z": "953e8740401d175c", + "g": "05cb4985c3c68ae8", + "name": "link out 3", + "mode": "link", + "links": [ + "423023a153680e64" + ], + "x": 2975, + "y": 1640, + "wires": [] } ] \ No newline at end of file diff --git a/uibuilder/totem/src/index.css b/uibuilder/totem/src/index.css index ac4b9b2..e881f2d 100644 --- a/uibuilder/totem/src/index.css +++ b/uibuilder/totem/src/index.css @@ -524,6 +524,59 @@ td[contenteditable="true"] { font-size: 12px; } } + +/* =============================== PANTALLA SENSOR AÑADIDO POR DAVID=============================== */ + +.sensor-info-block { + display: flex; + justify-content: space-between; + align-items: center; + margin: 10px 0; + padding: 10px 14px; + background: #f4f6f8; + border-radius: 8px; +} + +.sensor-label { + font-size: 14px; + font-weight: bold; + color: #555; +} + +.sensor-valor { + font-size: 28px; + font-weight: bold; + color: #2c3e50; +} + +.sensor-valor-min { + font-size: 22px; + font-weight: bold; + color: #e67e22; +} + +.sensor-barra-wrap { + padding: 0 4px; + +} + +.sensor-barra-bg { + position: relative; + height: 46px; + background: #dce3ea; + border-radius: 10px; + overflow: visible; + max-height: 20px; +} + +.sensor-barra-fill { + height: 100%; + width: 0%; + border-radius: 10px; + background: #3498db; + transition: width 0.5s ease, background-color 0.3s; +} + /*-------------------------------------------------- IMAGEN INICIAL DEL SNAPSHOT ---------------------------------------------------------------------*/ /* #foto { diff --git a/uibuilder/totem/src/index.html b/uibuilder/totem/src/index.html index 93cfd0a..404d816 100644 --- a/uibuilder/totem/src/index.html +++ b/uibuilder/totem/src/index.html @@ -112,6 +112,7 @@ + @@ -220,6 +221,35 @@ + +
+
+
+ +

Trypton Software

+
+

PRUEBA DEL SENSOR

+
+ +
+ Distancia mínima configurada + --- mm +
+ +
+ Distancia detectada + --- mm +
+ +
+
+
+
+
+ + +
+
diff --git a/uibuilder/totem/src/index.js b/uibuilder/totem/src/index.js index 202d6c5..71bfaa5 100644 --- a/uibuilder/totem/src/index.js +++ b/uibuilder/totem/src/index.js @@ -137,7 +137,26 @@ uibuilder.onChange('msg', msg => { if (msg.hasOwnProperty("totem_id")) document.getElementById('totem-id').textContent = msg.totem_id; if (msg.hasOwnProperty("iplan")) document.getElementById('iplan').textContent = msg.iplan; if (msg.hasOwnProperty("ipsupervisor")) document.getElementById('ipsupervisor').textContent = msg.ipsupervisor; + + // ======== Sensor de distancia añadido por david======== + if (msg.hasOwnProperty("distance")) { + const dist = msg.distance; + const dmin = msg.distance_min; + const maxRange = 4000; + document.getElementById('sensor-dist').textContent = + (dist !== null && dist !== undefined) ? dist + ' mm' : '--- mm'; + + if (dmin !== null && dmin !== undefined) { + document.getElementById('sensor-dmin').textContent = dmin + ' mm'; + } + + if (dist !== null && dist !== undefined) { + const fillPct = Math.min((dist / maxRange) * 100, 100); + const fill = document.getElementById('sensor-fill'); + fill.style.width = fillPct + '%'; + } + } }); //****************************************************************************************************************************************************** */