From 370ae5c4141bb27700c0104f897454df32862b8b Mon Sep 17 00:00:00 2001 From: trypton Date: Wed, 25 Mar 2026 17:18:29 +0100 Subject: [PATCH] =?UTF-8?q?=20Debido=20a=20nuevo=20requerimiento=20se=20in?= =?UTF-8?q?troduce=20la=20opcion=20(configurable)=20de=20tener=20una=20cam?= =?UTF-8?q?ara=20de=20contexto=20en=20la=20bascula.=20Esta=20camara=20en?= =?UTF-8?q?=20caso=20de=20estar=20habilitada=20en=20la=20configuracion=20t?= =?UTF-8?q?omara=20una=20imagen=20en=20el=20momento=20en=20que=20el=20cami?= =?UTF-8?q?on=20este=20completamente=20en=20la=20bascula,=20para=20ello=20?= =?UTF-8?q?hemos=20introducido=20un=20codigo=20en=20el=20nodo=20"estable"?= =?UTF-8?q?=20que=20es=20donde=20se=20hace=20la=20deteccion=20del=20camion?= =?UTF-8?q?=20completamente=20en=20la=20bascula.=20Posteriormente=20en=20e?= =?UTF-8?q?l=20nodo=20"Analisis=20del=20modo=20de=20Operacion"=20es=20dond?= =?UTF-8?q?e=20verificamos=20que=20la=20imagen=20fue=20tomada=20y=20la=20c?= =?UTF-8?q?olocamos=20en=20el=20registro=20que=20se=20esta=20haciendo=20pa?= =?UTF-8?q?ra=20generar=20el=20movimiento=20correspondiente.=20El=20Grupo?= =?UTF-8?q?=20"CAMARA=20CONTEXTO"=20posee=20los=20nodos=20de=20solicitud?= =?UTF-8?q?=20de=20imagen=20y=20de=20recepcion=20de=20la=20misma.=20La=20c?= =?UTF-8?q?onfiguracion=20de=20IP=20de=20la=20camara=20se=20hace=20en=20la?= =?UTF-8?q?=20pantalla=20de=20configuracion=20al=20igual=20que=20su=20habi?= =?UTF-8?q?litacion=20en=20el=20sistema.=20-=20Como=20herramienta=20de=20a?= =?UTF-8?q?yuda=20para=20saber=20si=20el=20Totem=20esta=20en=20capacidad?= =?UTF-8?q?=20de=20solicitar=20y=20de=20recibir=20la=20imagen=20de=20conte?= =?UTF-8?q?xto=20enviada=20por=20la=20camara=20se=20ha=20incluido=20una=20?= =?UTF-8?q?funcion=20en=20el=20menu=20de=20configuracion=20->=20Pruebas=20?= =?UTF-8?q?del=20sistema=20->=20Pedir=20Snapshot=20de=20contexto=20de=20fo?= =?UTF-8?q?rma=20que=20el=20usuario=20pueda=20visualizar=20la=20imagen=20a?= =?UTF-8?q?ctual=20que=20la=20camara=20esta=20enviando=20y=20pueda=20de=20?= =?UTF-8?q?esa=20forma=20confirmar=20el=20correcto=20funcionamiento=20de?= =?UTF-8?q?=20la=20conexi=C3=B3n=20y=20de=20los=20equipos.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bascula_autonoma_1.json | 483 ++++++++++++++++++++++++--------- bascula_autonoma_1_cred.json | 10 +- uibuilder/totem/src/index.css | 23 +- uibuilder/totem/src/index.html | 22 +- uibuilder/totem/src/index.js | 21 +- 5 files changed, 420 insertions(+), 139 deletions(-) diff --git a/bascula_autonoma_1.json b/bascula_autonoma_1.json index f007705..6b29a8a 100644 --- a/bascula_autonoma_1.json +++ b/bascula_autonoma_1.json @@ -235,7 +235,7 @@ "b5e1afed9e1c8376", "750c950486ec6cb1" ], - "x": 2274, + "x": 2474, "y": 959, "w": 812, "h": 342 @@ -279,17 +279,21 @@ "423023a153680e64", "fc6c8adcf31b5734", "6f9cc9fc71e8ca71", - "eed0d30668b76183", "cf7b0c00631682b2", "b2149025f64c76c7", "b6a2b0d90858876e", - "1210dd76a59df098", "7cb744ca5e4180bf", - "0fc258061e59d527" + "0fc258061e59d527", + "1b1ee13b380e32b6", + "31e0432a8e9a2f00", + "f3676f905e4ade55", + "730bbe3df0ab62db", + "ff3913749bd9e2f3", + "a0aa0f96fe081912" ], "x": 134, "y": 893, - "w": 2132, + "w": 2252, "h": 814 }, { @@ -394,11 +398,12 @@ "772b17b6e7954d5f", "7a4c757e6f6ddfcd", "6fca6204952f0b67", - "3a321a461f6a4531", "f4c61087c128e20f", "6d39924d1d2081dd", "8ccf22739ca72997", - "7fd2f6e6fe3f37ea" + "7fd2f6e6fe3f37ea", + "ee22e8c1327a7b65", + "b90652f4011dad39" ], "x": 3364, "y": 1999, @@ -589,11 +594,12 @@ "b31db528b0be605a", "185e340354acf892", "9d8e071a6d3642c0", - "77d23eabe6e7d642" + "77d23eabe6e7d642", + "c79815b5a79ef60a" ], "x": 994, "y": 919, - "w": 532, + "w": 572, "h": 510 }, { @@ -675,6 +681,30 @@ "w": 1352, "h": 329.5 }, + { + "id": "1b1ee13b380e32b6", + "type": "group", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "CAMARA CONTEXTO", + "style": { + "stroke": "#92d04f", + "fill": "#c8e7a7", + "fill-opacity": "0.29", + "label": true, + "color": "#000000" + }, + "nodes": [ + "72071eee550615d7", + "f5b38e6e811de790", + "9b0761cc102bc028", + "8385582377c91fb6" + ], + "x": 1594, + "y": 1339, + "w": 552, + "h": 82 + }, { "id": "3966bb218232f6b3", "type": "mqtt-broker", @@ -759,7 +789,7 @@ { "id": "be0e1690e4e13e0d", "type": "websocket-client", - "path": "ws://servidor.com:1880", + "path": "ws://servidor.com:25009", "tls": "", "wholemsg": "false", "hb": "20", @@ -1123,6 +1153,7 @@ "id": "8db77186d4b23dbc", "type": "mqtt out", "z": "953e8740401d175c", + "d": true, "name": "totem", "topic": "totemautonomo/", "qos": "2", @@ -2294,7 +2325,6 @@ [], [ "76877357b0cb15d2", - "fb6b2f1f9986070e", "55d3cd43f7070262" ] ] @@ -2707,7 +2737,7 @@ "z": "953e8740401d175c", "g": "0e2b148022a7af13", "name": " envia matricula", - "func": "if (!flow.get(\"plate_sent\") && !flow.get(\"peso_bajo_flag\")) {\n var timestamp = new Date().getTime()\n var plate = RED.util.cloneMessage(flow.get(\"last_plate\"))\n var plate_number = plate.payload.Picture.Plate.PlateNumber\n var plate_time = plate.payload.Picture.SnapInfo.SnapTime\n //node.send([{payload:plate.payload.Picture.NormalPic.Content, filename:\"/home/trypton/.node-red/dahua_images/\" + plate.payload.Picture.NormalPic.PicName}, null])\n flow.set(\"matricula\", plate_number)\n flow.set(\"matricula_image\", plate.payload.Picture.NormalPic.Content)\n flow.set(\"plate_sent\", true) // marcamos matricula enviada\n if (!flow.get(\"supervisor\")) {\n //node.warn(\"matricula leida\")\n flow.set(\"matricula_leida_flag\", true)\n //flow.set(\"nombre_imagen\", plate.payload.Picture.NormalPic.PicName)\n let now = new Date()\n let nowdate = now.toLocaleString(\"sv-SE\").replace(/[- :]/g, \"\")\n flow.set(\"nombre_imagen\", flow.get(\"matricula\") + \"-\" + nowdate + \".jpg\")\n if (plate_number == \"NOT FOUND\") {\n flow.set(\"matricula_formato_flag\", false)\n }\n else {\n let checkmatricula = checkPlateFormat(plate_number)\n flow.set(\"matricula_formato_flag\", checkmatricula.isValid)\n flow.set(\"matricula\", checkmatricula.formattedText)\n }\n\n msg = {}\n msg.payload = 1\n msg.topic = \"matricula_leida\"\n msg.matricula = flow.get(\"matricula\")\n\n node.send([null, msg, null]);\n }\n\n else { // caso supervisor = true\n if (!flow.get(\"peso_bajo_flag\")) {\n let msg_json = {}\n msg_json.payload = { numero_vial: flow.get(\"numero_vial\"), totem_id: flow.get(\"totem_id\"), \"matricula\": flow.get(\"matricula\"), \"foto_matricula\": flow.get(\"matricula_image\") }\n node.send([null, { payload: true }, msg_json]);\n }\n }\n}\nelse{//\n if(!flow.get(\"plate_sent\") && flow.get(\"anpr1_flag\")) {\n //Si estamos aqui es porque tenemos imagen tomada por request del detector pero la bascula no ha sido activada\n \n }\n}\nreturn\n\n/*******************************************************************************************\n * FUNCION DE CHEQUEO DEL FORMATO DE LA MATRICULA\n *******************************************************************************************\n*/\nfunction checkPlateFormat(plate) {\n\n let formatoPais = flow.get(\"formatoPais\")\n let match\n\n // Seleccion del formato\n if (formatoPais === \"es\") {\n //ESPAÑA\n const regex1 = /^(\\d{4}[A-Z]{3})(.*)$/i;\n const regex2 = /^([A-Z]{1,2}\\d{4}[A-Z]{2})(.*)$/i;\n match = plate.match(regex1) || plate.match(regex2);\n } if (formatoPais === \"co\") {\n //COLOMBIA\n const regexCargaGeneral = /^[A-Z]\\d{4}$/;\n const regexCargaT = /^T\\d{4}$/;\n const regexDiplomaticos = /^[A-Z]{2}\\d{4}$/;\n const regexParticulares = /^[A-Z]{3}\\d{3}$/;\n match = plate.match(regexCargaGeneral) || plate.match(regexCargaT) || plate.match(regexDiplomaticos) || plate.match(regexParticulares);\n }\n // Aplicacion del formato seleccionado\n flow.set(\"match\", match)\n if (match) {\n return {\n isValid: true,\n formattedText: match[0] // Solo tomamos el primer grupo de captura (la matrícula válida)\n };\n } else {\n return {\n isValid: false,\n formattedText: plate\n };\n }\n}\n\n\n\n\n\n\n\n\n\n\n/*******************************************************************************************\n * FUNCION DE CHEQUEO DEL FORMATO DE LA MATRICULA\n *******************************************************************************************\n * Esta funcion chequea:\n * 1.- si el formato de la matricula se corresponde con 4 numeros y 3 letras o bien con 1 o 2 letras, 4 nuemros y 2 letras\n * 2.- si tiene letras adicionales al final de la matricula (como SP), las elimina \n * 3.- devuelve validez del formato y contenidos de la matricula\n*/\n/*\nfunction checkPlateFormat(plate) {\n // Expresiones regulares para los dos formatos, capturando cualquier cosa extra al final\n // En el formato 1 el primer grupo de captura contiene los caracteres permitidos de la matricula (\\d{4}[A-Z]{3}) y el segundo grupo de captura (.*) los caracteres que no queremos\n // En el formato 2 el primer grupo de captura contiene los caracteres permitidos de la matricula ([A-Z]{1,2}\\d{4}[A-Z]{2}) y el segundo grupo de captura (.*) los caracteres que no queremos\n const regex1 = /^(\\d{4}[A-Z]{3})(.*)$/i;\n const regex2 = /^([A-Z]{1,2}\\d{4}[A-Z]{2})(.*)$/i;\n\n let match = plate.match(regex1) || plate.match(regex2);\n flow.set(\"match\", match)\n if (match) {\n return {\n isValid: true,\n formattedText: match[1] // Solo tomamos el primer grupo de captura (la matrícula válida)\n };\n } else {\n return {\n isValid: false,\n formattedText: plate\n };\n }\n}\n*/", + "func": "if (!flow.get(\"plate_sent\") && !flow.get(\"peso_bajo_flag\")) {\n var timestamp = new Date().getTime()\n var plate = RED.util.cloneMessage(flow.get(\"last_plate\"))\n var plate_number = plate.payload.Picture.Plate.PlateNumber\n var plate_time = plate.payload.Picture.SnapInfo.SnapTime\n //node.send([{payload:plate.payload.Picture.NormalPic.Content, filename:\"/home/trypton/.node-red/dahua_images/\" + plate.payload.Picture.NormalPic.PicName}, null])\n flow.set(\"matricula\", plate_number)\n flow.set(\"matricula_image\", plate.payload.Picture.NormalPic.Content) // Recuperamos y guardamos foto del vehiculo\n flow.set(\"plate_sent\", true) // marcamos matricula enviada\n if (!flow.get(\"supervisor\")) {\n //node.warn(\"matricula leida\")\n flow.set(\"matricula_leida_flag\", true)\n //flow.set(\"nombre_imagen\", plate.payload.Picture.NormalPic.PicName)\n let now = new Date()\n let nowdate = now.toLocaleString(\"sv-SE\").replace(/[- :]/g, \"\")\n flow.set(\"nombre_imagen\", flow.get(\"matricula\") + \"-\" + nowdate + \".jpg\")\n if (plate_number == \"NOT FOUND\") {\n flow.set(\"matricula_formato_flag\", false)\n }\n else {\n let checkmatricula = checkPlateFormat(plate_number)\n flow.set(\"matricula_formato_flag\", checkmatricula.isValid)\n flow.set(\"matricula\", checkmatricula.formattedText)\n }\n\n msg = {}\n msg.payload = 1\n msg.topic = \"matricula_leida\"\n msg.matricula = flow.get(\"matricula\")\n\n node.send([null, msg, null]);\n }\n\n else { // caso supervisor = true\n if (!flow.get(\"peso_bajo_flag\")) {\n let msg_json = {}\n msg_json.payload = { numero_vial: flow.get(\"numero_vial\"), totem_id: flow.get(\"totem_id\"), \"matricula\": flow.get(\"matricula\"), \"foto_matricula\": flow.get(\"matricula_image\") }\n node.send([null, { payload: true }, msg_json]);\n }\n }\n}\nelse{//\n if(!flow.get(\"plate_sent\") && flow.get(\"anpr1_flag\")) {\n //Si estamos aqui es porque tenemos imagen tomada por request del detector pero la bascula no ha sido activada\n \n }\n}\nreturn\n\n/*******************************************************************************************\n * FUNCION DE CHEQUEO DEL FORMATO DE LA MATRICULA\n *******************************************************************************************\n*/\nfunction checkPlateFormat(plate) {\n\n let formatoPais = flow.get(\"formatoPais\")\n let match\n\n // Seleccion del formato\n if (formatoPais === \"es\") {\n //ESPAÑA\n const regex1 = /^(\\d{4}[A-Z]{3})(.*)$/i;\n const regex2 = /^([A-Z]{1,2}\\d{4}[A-Z]{2})(.*)$/i;\n match = plate.match(regex1) || plate.match(regex2);\n } if (formatoPais === \"co\") {\n //COLOMBIA\n const regexCargaGeneral = /^[A-Z]\\d{4}$/;\n const regexCargaT = /^T\\d{4}$/;\n const regexDiplomaticos = /^[A-Z]{2}\\d{4}$/;\n const regexParticulares = /^[A-Z]{3}\\d{3}$/;\n match = plate.match(regexCargaGeneral) || plate.match(regexCargaT) || plate.match(regexDiplomaticos) || plate.match(regexParticulares);\n }\n // Aplicacion del formato seleccionado\n flow.set(\"match\", match)\n if (match) {\n return {\n isValid: true,\n formattedText: match[0] // Solo tomamos el primer grupo de captura (la matrícula válida)\n };\n } else {\n return {\n isValid: false,\n formattedText: plate\n };\n }\n}\n\n\n\n\n\n\n\n\n\n\n/*******************************************************************************************\n * FUNCION DE CHEQUEO DEL FORMATO DE LA MATRICULA\n *******************************************************************************************\n * Esta funcion chequea:\n * 1.- si el formato de la matricula se corresponde con 4 numeros y 3 letras o bien con 1 o 2 letras, 4 nuemros y 2 letras\n * 2.- si tiene letras adicionales al final de la matricula (como SP), las elimina \n * 3.- devuelve validez del formato y contenidos de la matricula\n*/\n/*\nfunction checkPlateFormat(plate) {\n // Expresiones regulares para los dos formatos, capturando cualquier cosa extra al final\n // En el formato 1 el primer grupo de captura contiene los caracteres permitidos de la matricula (\\d{4}[A-Z]{3}) y el segundo grupo de captura (.*) los caracteres que no queremos\n // En el formato 2 el primer grupo de captura contiene los caracteres permitidos de la matricula ([A-Z]{1,2}\\d{4}[A-Z]{2}) y el segundo grupo de captura (.*) los caracteres que no queremos\n const regex1 = /^(\\d{4}[A-Z]{3})(.*)$/i;\n const regex2 = /^([A-Z]{1,2}\\d{4}[A-Z]{2})(.*)$/i;\n\n let match = plate.match(regex1) || plate.match(regex2);\n flow.set(\"match\", match)\n if (match) {\n return {\n isValid: true,\n formattedText: match[1] // Solo tomamos el primer grupo de captura (la matrícula válida)\n };\n } else {\n return {\n isValid: false,\n formattedText: plate\n };\n }\n}\n*/", "outputs": 3, "timeout": 0, "noerr": 0, @@ -3174,7 +3204,7 @@ "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 2350, + "x": 2550, "y": 1080, "wires": [ [] @@ -3196,7 +3226,7 @@ "resendOnRefresh": true, "templateScope": "local", "className": "widget_semaforo", - "x": 2360, + "x": 2560, "y": 1040, "wires": [ [] @@ -3218,7 +3248,7 @@ "resendOnRefresh": false, "templateScope": "local", "className": "widget_matricula", - "x": 2360, + "x": 2560, "y": 1160, "wires": [ [ @@ -3242,7 +3272,7 @@ "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 2370, + "x": 2570, "y": 1120, "wires": [ [ @@ -3264,7 +3294,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 2560, + "x": 2760, "y": 1060, "wires": [ [ @@ -3289,7 +3319,7 @@ "links": [ "0df0c819dae1658d" ], - "x": 2705, + "x": 2905, "y": 1060, "wires": [] }, @@ -3309,7 +3339,7 @@ "resendOnRefresh": true, "templateScope": "global", "className": "", - "x": 2360, + "x": 2560, "y": 1200, "wires": [ [] @@ -3328,7 +3358,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 3000, + "x": 3200, "y": 1120, "wires": [ [ @@ -3350,7 +3380,7 @@ "winHide": false, "oldrc": false, "name": "ip eth0", - "x": 3010, + "x": 3210, "y": 1180, "wires": [ [ @@ -3372,7 +3402,7 @@ "e0b4dd6107f95f28", "e771c9458e352071" ], - "x": 2705, + "x": 2905, "y": 1020, "wires": [] }, @@ -3386,7 +3416,7 @@ "links": [ "8356acc61776cae7" ], - "x": 2875, + "x": 3075, "y": 1200, "wires": [] }, @@ -3403,7 +3433,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 2730, + "x": 2930, "y": 1160, "wires": [ [ @@ -3437,7 +3467,7 @@ "topic": "", "payload": "1", "payloadType": "num", - "x": 2870, + "x": 3070, "y": 1260, "wires": [ [ @@ -3540,8 +3570,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 1910, - "y": 1220, + "x": 1970, + "y": 1160, "wires": [ [ "338d3caabc377186", @@ -3603,8 +3633,8 @@ "freq": "", "out": "out", "bcm": true, - "x": 2100, - "y": 1300, + "x": 2280, + "y": 1240, "wires": [] }, { @@ -3681,8 +3711,8 @@ "links": [ "cd806a312b8e7e6e" ], - "x": 1925, - "y": 1300, + "x": 2165, + "y": 1260, "wires": [ [ "422897281c1c5ef6" @@ -3872,8 +3902,8 @@ "links": [ "f47c019e5baa0206" ], - "x": 2065, - "y": 1360, + "x": 2225, + "y": 1380, "wires": [] }, { @@ -3907,7 +3937,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 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", + "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(\"nombre_contexto\", \"\") //inicializamos nombre de la imagen de la camara de contexto en vacio\n flow.set(\"last_camara_contexto\", \"\") // Inicializamos contenido de la imagen de contexto\n flow.set(\"badplate\", false)\n //flow.set(\"distance_flag_SET\", false) // Si dejamos esta inicializacion puede bloquear el detector de vehiculos y dejarlo en estado Ocupado\n //Poner este flag en false mientras el detector esta contando los pulsos de salida hace que no pueda entrar en la zona de puesta en cero (OFF)\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, @@ -3948,14 +3978,14 @@ "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 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])", + "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 let imagen_contexto_ok = flow.get(\"camara_contexto_rx\") || !flow.get(\"camara_contexto\") \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 && imagen_contexto_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 new_register.nombre_contexto = flow.get(\"nombre_contexto\") // el nombre se asigna al recibir la imagen en el nodo \"convert to base64\"\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(\"camara_contexto\")) {\n new_register.imagen_contexto = flow.get(\"last_camara_contexto\")\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 if(flow.get(\"camara_contexto\")){\n new_register.imagen_contexto = flow.get(\"last_camara_contexto\")\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, "initialize": "", "finalize": "", "libs": [], - "x": 1630, + "x": 1730, "y": 1140, "wires": [ [ @@ -3965,8 +3995,7 @@ "fab29e0f6601e531" ], [ - "b6a2b0d90858876e", - "1210dd76a59df098" + "b6a2b0d90858876e" ], [ "48eda297.9cdedc" @@ -3986,8 +4015,8 @@ "links": [ "8356acc61776cae7" ], - "x": 1855, - "y": 1080, + "x": 1925, + "y": 1020, "wires": [] }, { @@ -4000,8 +4029,8 @@ "links": [ "f47c019e5baa0206" ], - "x": 1855, - "y": 1120, + "x": 1925, + "y": 1060, "wires": [] }, { @@ -4016,8 +4045,8 @@ "freq": "", "out": "out", "bcm": true, - "x": 2180, - "y": 1220, + "x": 2300, + "y": 1180, "wires": [] }, { @@ -4030,8 +4059,8 @@ "links": [ "0df085dfc5184645" ], - "x": 1435, - "y": 1220, + "x": 1515, + "y": 1240, "wires": [] }, { @@ -4127,8 +4156,8 @@ "className": "", "topic": "", "name": "edit plate", - "x": 1340, - "y": 1220, + "x": 1400, + "y": 1240, "wires": [ [ "77d23eabe6e7d642" @@ -4173,8 +4202,8 @@ "z": "953e8740401d175c", "g": "9328043d4e9512a9", "name": "estable", - "func": "//****************************************Chequeo de Peso Estable ********************************************\n// El peso estable es el peso leido en cualquier de los siguientes momentos:\n// 1. Al Recibir un QR o RFID\n// 2. Cuando el Detector de presencia en el Totem es ON (distance_flag_SET)\n// 3. Cuando se activa el Boton de Validacion (salida_valida_flag true)\n// 4. Cuando el usuario envia la seleccion del menu en caso de que este habilitado (menu_seleccionado_flag)\n// 5. Cuando el usuario acepta el editor de matricula\n\nif (((flow.get(\"distance_flag_SET\") || flow.get(\"QR_ok_flag\") || flow.get(\"RFID_ok_flag\") || flow.get(\"salida_valida_flag\") || flow.get(\"vehiculo_en_posicion\")) || flow.get(\"editor_matricula_ok\")) && !flow.get(\"peso_bajo_flag\") && !flow.get(\"peso_estable_flag\") && flow.get(\"totem_master\") && !flow.get(\"supervisor\") ) {//aseguramos se hace una sola vez durante la pesada\n flow.set(\"peso_estable\", flow.get(\"peso\"))\n //node.warn(\"peso = \" + flow.get(\"peso_estable\") + \" pma = \" + flow.get(\"pma\") + \"pma - peso = \" + (flow.get(\"pma\") - flow.get(\"peso_estable\")))\n // chequeamos si el peso del vehiculo es inferior al Peso Maximo Autorizado (PMA)\n if ((flow.get(\"pma\") > 0 && (flow.get(\"pma\") - flow.get(\"peso_estable\")) < 0)) {\n \n if (!flow.get(\"aviso_pma_hecho\")) {\n node.send([null, null, { payload: \"

PESO EXCEDIDO

SALGA DE LA BASCULA

\" }])\n flow.set(\"aviso_pma_hecho\", true) // hacemos el aviso una sola vez en la pesada\n }\n }\n else {\n if (!flow.get(\"peso_estable_flag\")) { // solo emitimos audio y mensaje una sola vez durante la misma pesada\n flow.set(\"peso_estable_flag\", true)\n node.send([{ payload: \"peso_estable\" }, null]) // activa audio de peso estable\n flow.set(\"window_men_m1\", flow.get(\"men_peso_estable\")); //se envia mensaje de Peso estable en pantalla\n }\n\n }\n\n \n}\nelse if (flow.get(\"supervisor\") && flow.get(\"peso_estable_flag\") && flow.get(\"peso_estable_audio_flag\")){\n flow.set(\"window_men_m1\", flow.get(\"men_peso_estable\")); //se envia mensaje de Peso estable en pantalla\n flow.set(\"peso_estable_audio_flag\", false)\n node.send([{ payload: \"peso_estable\" }, null]) // activa audio de peso estable\n}\n //*************************************************************************************************************\n\nreturn ([null, msg]);", - "outputs": 3, + "func": "//****************************************Chequeo de Peso Estable ********************************************\n// El peso estable es el peso leido en cualquier de los siguientes momentos:\n// 1. Al Recibir un QR o RFID\n// 2. Cuando el Detector de presencia en el Totem es ON (distance_flag_SET)\n// 3. Cuando se activa el Boton de Validacion (salida_valida_flag true)\n// 4. Cuando el usuario envia la seleccion del menu en caso de que este habilitado (menu_seleccionado_flag)\n// 5. Cuando el usuario acepta el editor de matricula\n\nif (((flow.get(\"distance_flag_SET\") || flow.get(\"QR_ok_flag\") || flow.get(\"RFID_ok_flag\") || flow.get(\"salida_valida_flag\") || flow.get(\"vehiculo_en_posicion\")) || flow.get(\"editor_matricula_ok\")) && !flow.get(\"peso_bajo_flag\") && !flow.get(\"peso_estable_flag\") && flow.get(\"totem_master\") && !flow.get(\"supervisor\") ) {//aseguramos se hace una sola vez durante la pesada\n flow.set(\"peso_estable\", flow.get(\"peso\"))\n //node.warn(\"peso = \" + flow.get(\"peso_estable\") + \" pma = \" + flow.get(\"pma\") + \"pma - peso = \" + (flow.get(\"pma\") - flow.get(\"peso_estable\")))\n // chequeamos si el peso del vehiculo es inferior al Peso Maximo Autorizado (PMA)\n if ((flow.get(\"pma\") > 0 && (flow.get(\"pma\") - flow.get(\"peso_estable\")) < 0)) {\n \n if (!flow.get(\"aviso_pma_hecho\")) {\n node.send([null, null, { payload: \"

PESO EXCEDIDO

SALGA DE LA BASCULA

\" }])\n flow.set(\"aviso_pma_hecho\", true) // hacemos el aviso una sola vez en la pesada\n }\n }\n else {\n if (!flow.get(\"peso_estable_flag\")) { // solo emitimos audio y mensaje una sola vez durante la misma pesada\n flow.set(\"peso_estable_flag\", true)\n node.send([{ payload: \"peso_estable\" }, null]) // activa audio de peso estable\n flow.set(\"window_men_m1\", flow.get(\"men_peso_estable\")); //se envia mensaje de Peso estable en pantalla\n }\n\n }\n//Solicitamos Imagen de la camara de contexto\n if (flow.get(\"camara_contexto\")){\n let msg_camara_contexto = {}\n msg_camara_contexto.url = `http://${flow.get(\"camara_contexto_IP\")}/cgi-bin/snapshot.cgi?channel=1`\n flow.set(\"camara_contexto_rx\", false) // inicializamos flag de imagen no recibida de la camara de contexto\n node.send ([null, null, null, msg_camara_contexto])\n }\n \n}\nelse if (flow.get(\"supervisor\") && flow.get(\"peso_estable_flag\") && flow.get(\"peso_estable_audio_flag\")){\n flow.set(\"window_men_m1\", flow.get(\"men_peso_estable\")); //se envia mensaje de Peso estable en pantalla\n flow.set(\"peso_estable_audio_flag\", false)\n node.send([{ payload: \"peso_estable\" }, null]) // activa audio de peso estable\n}\n //*************************************************************************************************************\n\nreturn ([null, msg]);", + "outputs": 4, "timeout": 0, "noerr": 0, "initialize": "", @@ -4191,6 +4220,9 @@ ], [ "f5343bf87806ece4" + ], + [ + "c79815b5a79ef60a" ] ] }, @@ -4297,8 +4329,8 @@ "links": [ "656a6ccd2e2d8874" ], - "x": 2085, - "y": 1080, + "x": 2105, + "y": 1040, "wires": [] }, { @@ -4346,8 +4378,8 @@ "6fca6204952f0b67", "cf7b0c00631682b2" ], - "x": 2065, - "y": 1260, + "x": 2145, + "y": 1200, "wires": [ [ "a862be7fbfd8827a" @@ -5122,8 +5154,8 @@ "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 //------------------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, + "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 //flow.set(\"context_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 case \"repetir\":\n case \"contexto\" : // boton para pedir snapshot de camara de contexto\n flow.set(\"context_cam\", true)\n flow.set(\"escuchar_cam\", false)\n //flow.set(\"snapshot_cam\", false)\n let msgrqt2 = {}\n msgrqt2.payload = {}\n msgrqt2.url = \"http://\" + flow.get(\"camara_contexto_IP\") + \"/cgi-bin/snapshot.cgi?channel=1\"\n msgrqt2.topic = \"context_rqtd\"\n return ([{ payload: { pantalla: \"contexto\" }, topic: \"contexto\" }, null, null, null, null, null, null, null, msgrqt2])\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 //flow.set(\"context_cam\", false)\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 flow.set(\"context_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": 9, "timeout": 0, "noerr": 0, "initialize": "", @@ -5137,7 +5169,6 @@ "207488e79f57a0eb" ], [ - "f4c61087c128e20f", "6d39924d1d2081dd" ], [ @@ -5156,8 +5187,10 @@ "772b17b6e7954d5f" ], [ - "6fca6204952f0b67", - "3a321a461f6a4531" + "6fca6204952f0b67" + ], + [ + "ee22e8c1327a7b65" ] ] }, @@ -5216,7 +5249,8 @@ "links": [ "1ee7d9733d5bdccd", "88b9b4d1c5aa7359", - "ade2db3a9cf2dab1" + "ade2db3a9cf2dab1", + "b90652f4011dad39" ], "x": 3535, "y": 2180, @@ -5278,7 +5312,7 @@ "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 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}", + "func": "if(msg.payload.hasOwnProperty(\"tiposDatos\")){\n return(msg)\n\n}\nelse { //Aqui analizamos las imagenes de las camaras y lo relacionado con los botones de configuracion para la visualizacion de camaras\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 else if (flow.get(\"context_cam\") && msg.topic === \"context_rqtd\") { // si recibimos snapshot de camara de contexto\n if (Buffer.isBuffer(msg.payload)) {\n msg.payload = msg.payload.toString('base64');\n }\n msgmix.picture_contexto = \"data:image/png;base64,\" + msg.payload\n let date = new Date();\n msgmix.fecha_contexto = new Date(date.getTime()).toLocaleString()\n \n msg.payload = {}\n \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.context_cam = flow.get(\"context_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, @@ -5349,7 +5383,7 @@ "z": "953e8740401d175c", "g": "e3bc37824e09b774", "name": "debug 18", - "active": false, + "active": true, "tosidebar": true, "console": false, "tostatus": false, @@ -5386,24 +5420,6 @@ "y": 2400, "wires": [] }, - { - "id": "3a321a461f6a4531", - "type": "debug", - "z": "953e8740401d175c", - "g": "e3bc37824e09b774", - "name": "debug 27", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 4360, - "y": 2440, - "wires": [] - }, { "id": "1826a83d58a7539b", "type": "uibuilder", @@ -5770,7 +5786,7 @@ "z": "953e8740401d175c", "g": "595fb0f89af85c42", "name": "config edit", - "func": "const config = JSON.parse(msg.payload);\nmsg ={}; // clear msg object\nlet read;\nlet config_general = []\nlet config_tiempos = []\nlet config_mensajes = []\nlet config_sensor = []\nlet config_camara = []\nlet config_conex = []\nlet config_tipos = []\n\nconfig.general = toObject(config.general);\nconfig.camara = toObject(config.camara);\nconfig.conexion = toObject(config.conexion);\nconfig.sensores = toObject(config.sensores);\nconfig.mensajes = toObject(config.mensajes);\nconfig.tiempos = toObject(config.tiempos);\n\nconst tiposOriginales = config.tipos || {};\n\n\n// Aseguramos que cada tipo esté como array vacío si no tiene nada\nfor (let i = 1; i <= 6; i++) {\n if (!Array.isArray(tiposOriginales[i])) {\n tiposOriginales[i] = [];\n }\n}\nflow.set(\"tiposDatosGlobal\", tiposOriginales);\n\nconfig.tipos = tiposOriginales;\n\n\n\n//**************************** Parametros de Validacion OBLIGATORIOS para PESADA FINALIZADA ***************************************\n// Estos parametros pueden ser: QR / RFID / Boton Validacion / Detector Vehiculo \n//*********************************************************************************************************************************\n/*read = config.QR_obligatorio;\nconfig_general.push({ \"parametro\": \"QR_obligatorio\", \"valor\": read })\nflow.set(\"QR_obligatorio\", read);\nread = config.RFID_obligatorio;\nconfig_general.push({ \"parametro\": \"RFID_obligatorio\", \"valor\": read })\nflow.set(\"RFID_obligatorio\", read);\n\nread = config.general.funcion_totem;\nconfig_general.push({ \"parametro\": \"funcion_totem\", \"valor\": read })\nflow.set(\"funcion_totem\", read);\n\nread = config.general.identificacion_esp;\nconfig_general.push({ \"parametro\": \"identificacion_esp\", \"valor\": read })\nflow.set(\"identificacion_esp\", read);\n\nread = config.tiempos.timer1;\nconfig_tiempos.push({ \"parametro\": \"timer1\", \"valor\": read })\nflow.set(\"timer1\", read);\n\n*/\n\nread = config.general.Tipo_Configuracion;\nconfig_general.push({ \"parametro\": \"Tipo_Configuracion\", \"valor\": read })\nflow.set(\"Tipo_Configuracion\", read);\n\nread = config.general.ID_obligatorio;\nconfig_general.push({ \"parametro\": \"ID_obligatorio\", \"valor\": read })\nflow.set(\"ID_obligatorio\", read);\n\nread = config.general.salida_ID_obligatorio;\nconfig_general.push({ \"parametro\": \"salida_ID_obligatorio\", \"valor\": read })\nflow.set(\"salida_ID_obligatorio\", read);\n\nread = config.general.detector_obligatorio;\nconfig_general.push({ \"parametro\": \"detector_obligatorio\", \"valor\": read })\nflow.set(\"detector_obligatorio\", read);\n\nread = config.general.boton_obligatorio;\nconfig_general.push({ \"parametro\": \"boton_obligatorio\", \"valor\": read })\nflow.set(\"boton_obligatorio\", read);\nread = config.general.firma_obligatoria;\nconfig_general.push({ \"parametro\": \"firma_obligatoria\", \"valor\": read })\nflow.set(\"firma_obligatoria\", read);\nread = config.general.matricula_obligatoria;\nconfig_general.push({ \"parametro\": \"matricula_obligatoria\", \"valor\": read })\nflow.set(\"matricula_obligatoria\", read);\n\n\n\n//==================================================================================================================================\nread = config.general.edicion_matricula;\nconfig_general.push({ \"parametro\": \"edicion_matricula\", \"valor\": read })\nflow.set(\"edicion_matricula\", read); // Habilita la edicion de matricula\n\nread = config.general.botonsalida_activo;\nconfig_general.push({ \"parametro\": \"botonsalida_activo\", \"valor\": read })\nflow.set(\"botonsalida_activo\", read); // Permite poner boton de salida\n\nread = config.general.menu_activo;\nconfig_general.push({ \"parametro\": \"menu_activo\", \"valor\": read })\nflow.set(\"menu_activo\", read); // Permite poner los menus de contratacion\n\n/*\nread = config.general.firma_habilitada;\nconfig_general.push({ \"parametro\": \"firma_habilitada\", \"valor\": read })\nflow.set(\"firma_habilitada\", read); // Habilita la edicion de firma\n*/\n\nread = config.general.barrera_habilitada;\nconfig_general.push({ \"parametro\": \"barrera_habilitada\", \"valor\": read })\nflow.set(\"barrera_habilitada\", read); // Habilita el uso de barrera\n\nread = config.general.mostrar_ubicacion\nconfig_general.push({ \"parametro\": \"mostrar_ubicacion\", \"valor\": read })\nflow.set(\"mostrar_ubicacion\", read);\n\nread = config.general.switch_2_Totem_page;\nflow.set(\"switch_2_Totem_page\", read); // si igual a true cambia a pagina principal del totem siempre que se active la bascula\n// Con esto aseguramos que si queda abierta una ventana de configuracion se pueda quitar automaticamente\nconfig_general.push({ \"parametro\": \"switch_2_Totem_page\", \"valor\": read })\n\n//flow.set(\"peso\", read); // crea variable para recibir peso del supervisor\n\nread = parseInt(config.general.peso_minimo); // peso minimo para utilizado para indicar cuando hay vehiculo en la balanza o no\nconfig_general.push({ \"parametro\": \"peso_minimo\", \"valor\": read })\nflow.set(\"peso_minimo\", read);\n\nread = config.general.formatoPais; // peso minimo para utilizado para indicar cuando hay vehiculo en la balanza o no\nconfig_general.push({ \"parametro\": \"formatoPais\", \"valor\": read })\nflow.set(\"formatoPais\", read);\n\n//------------------- TOTEM MASTER tiempo de confirmacion -------------------------------------\nread = config.tiempos.confirm_master_time;\nconfig_tiempos.push({ \"parametro\": \"confirm_master_time\", \"valor\": read })\nflow.set(\"confirm_master_time\", read);\n//---------------------------------------------------------------------------------------------\n\n\nread = config.general.audio_level;\nconfig_general.push({ \"parametro\": \"audio_level\", \"valor\": read })\nflow.set(\"audio_level\", read);\n//-------------------------------------------------------\nread = config.general.mante_code_RFID; //codigo RFID para pasar a pantalla de mantenimiento\nconfig_general.push({ \"parametro\": \"mante_code_RFID\", \"valor\": read })\nflow.set(\"mante_code_RFID\", read)\nread = config.general.mante_code_QR; //codigo QR para pasar a pantalla de mantenimiento\nconfig_general.push({ \"parametro\": \"mante_code_QR\", \"valor\": read })\nflow.set(\"mante_code_QR\", read)\n\n//------------------------------- MENSAJES -------------------------\nread = config.tiempos.tiempo_mensaje;\nconfig_tiempos.push({ \"parametro\": \"tiempo_mensaje\", \"valor\": read })\nflow.set(\"tiempo_mensaje\", read);\n\nread = config.tiempos.relay2_pulse // duración del pulso generado en el relay 2 al terminar el pesaje para abrir barrera\nconfig_tiempos.push({ \"parametro\": \"relay2_pulse\", \"valor\": read })\nflow.set(\"relay2_pulse\", read);\n\nread = config.mensajes.mensaje2 // no se usa\nconfig_mensajes.push({ \"parametro\": \"mensaje2\", \"valor\": read })\nflow.set(\"mensaje2\", read);\nread = config.mensajes.mensaje1 // no se usa\nconfig_mensajes.push({ \"parametro\": \"mensaje1\", \"valor\": read })\nflow.set(\"mensaje1\", read);\nread = config.general.init_screen\nconfig_general.push({ \"parametro\": \"init_screen\", \"valor\": read })\nflow.set(\"init_screen\", read);\n\n//-------------------------------------------------------\nread = config.general.totem_serial // seriall asignado a este dispositivo\nconfig_general.push({ \"parametro\": \"totem_serial\", \"valor\": read })\nflow.set(\"totem_serial\", read);\n\n//---------------------------------------- Parametros por defecto del boton de salida para VALIDACION -----------------------------------------------------------\nread = config.mensajes.botonsalida_txt_def\nconfig_mensajes.push({ \"parametro\": \"botonsalida_txt_def\", \"valor\": read })\nflow.set(\"botonsalida_txt_def\", read)\nread = config.general.botonsalida_color_def\nconfig_general.push({ \"parametro\": \"botonsalida_color_def\", \"valor\": read })\nflow.set(\"botonsalida_color_def\", read)\nread = config.general.botonsalida_txt_color_def\nconfig_general.push({ \"parametro\": \"botonsalida_txt_color_def\", \"valor\": read })\nflow.set(\"botonsalida_txt_color_def\", read)\nread = config.mensajes.botonsalida_mensaje1\nconfig_mensajes.push({ \"parametro\": \"botonsalida_mensaje1\", \"valor\": read })\nflow.set(\"botonsalida_mensaje1\", read)\nread = config.mensajes.botonsalida_mensaje1_def\nconfig_mensajes.push({ \"parametro\": \"botonsalida_mensaje1_def\", \"valor\": read })\nflow.set(\"botonsalida_mensaje1_def\", read)\n\n//----------------------------------------- Textos Predefinidos -------------------------------------------------------------------------\nread = config.mensajes.men_pesaje_listo;\nconfig_mensajes.push({ \"parametro\": \"men_pesaje_listo\", \"valor\": read })\nflow.set(\"men_pesaje_listo\", read);\nread = config.mensajes.men_peso_estable;\nconfig_mensajes.push({ \"parametro\": \"men_peso_estable\", \"valor\": read })\nflow.set(\"men_peso_estable\", read);\nread = config.mensajes.men_identificacion;\nconfig_mensajes.push({ \"parametro\": \"men_identificacion\", \"valor\": read })\nflow.set(\"men_identificacion\", read);\nread = config.mensajes.men_salida;\nconfig_mensajes.push({ \"parametro\": \"men_salida\", \"valor\": read })\nflow.set(\"men_salida\", read);\nread = config.mensajes.id_titulo_matricula;\nconfig_mensajes.push({ \"parametro\": \"id_titulo_matricula\", \"valor\": read })\nflow.set(\"id_titulo_matricula\", read);\nread = config.mensajes.id_titulo_id;\nconfig_mensajes.push({ \"parametro\": \"id_titulo_id\", \"valor\": read })\nflow.set(\"id_titulo_id\", read);\nread = config.mensajes.id_leido;\nconfig_mensajes.push({ \"parametro\": \"id_leido\", \"valor\": read })\nflow.set(\"id_leido\", read);\nread = config.mensajes.id_no_leido;\nconfig_mensajes.push({ \"parametro\": \"id_no_leido\", \"valor\": read })\nflow.set(\"id_no_leido\", read);\n\n//===================================================CONEXION / CAMARA / SENSOR =====================================================\n//====================================================================================================================================\n\n\nread = config.conexion.modo_totem;\nconfig_conex.push({ \"parametro\": \"modo_totem\", \"valor\": read })\nflow.set(\"modo_totem\", read); // Modo de funcionamiento del totem\n\n\n//-----------------------------Gestion de IP fija / IP DHCP------------------------------------------------------\nvar ipdevice_flag = false // variables temporales para saber si hay cambios en las ip\nvar iprouter_flag = false\nread = config.conexion.ipdevice // direccion IP del dispositivo\nconfig_conex.push({ \"parametro\": \"ipdevice\", \"valor\": read })\nif (flow.get(\"ipdevice\") != read) {\n flow.set(\"ipdevice\", read);\n ipdevice_flag = true;\n}\nread = config.conexion.iprouter // direccion IP del router\nconfig_conex.push({ \"parametro\": \"iprouter\", \"valor\": read })\nif (flow.get(\"iprouter\") != read) {\n flow.set(\"iprouter\", read);\n iprouter_flag = true;\n}\nread = config.conexion.dhcp_flag // flag del DHCP\nconfig_conex.push({ \"parametro\": \"dhcp_flag\", \"valor\": read })\nif (flow.get(\"dhcp_flag\") != read) {\n flow.set(\"dhcp_flag\", read); // el dhcp_flag ha cambiado\n if (flow.get(\"dhcp_flag\")) {\n node.send([null, { payload: \". /home/trypton/scripts/enable_dhcp.sh\" }])\n }\n else {\n node.send([null, { payload: \". /home/trypton/scripts/enable_ipstatic.sh \" + flow.get(\"ipdevice\") + \"/24 \" + flow.get(\"iprouter\") }])\n }\n}\nelse { // el dhcp_flag no ha cambiado\n if (!flow.get(\"dhcp_flag\")) {\n if (ipdevice_flag || iprouter_flag) {\n node.send([null, { payload: \". /home/trypton/scripts/enable_ipstatic.sh \" + flow.get(\"ipdevice\") + \"/24 \" + flow.get(\"iprouter\") }])\n }\n }\n else {\n node.send([null, { payload: \". /home/trypton/scripts/enable_dhcp.sh\" }])\n }\n}\nflow.set(\"dhcpname_on\", \"IP Fija\") // texto que sale en el boton de la pantalla de mantenimiento\nflow.set(\"dhcpname_off\", \"DHCP\")\n//-----------------------------------Websocket IP--------------------------------------------------------------------------------------\nread = config.conexion.websocket_puerto // direccion IP del websocket del supervisor\nconfig_conex.push({ \"parametro\": \"websocket_puerto\", \"valor\": read })\nflow.set(\"websocket_puerto\", read);\nread = config.conexion.websocket_url\nconfig_conex.push({ \"parametro\": \"websocket_url\", \"valor\": read })\nif (flow.get(\"websocket_url\") != read) {\n flow.set(\"websocket_url\", read);\n node.send([{ payload: read + \" servidor.com\" }, null])\n}\n//----------------------------------- ENVIO DE MOVIMIENTOS --------------------------------------------------------------------------------------\nread = config.conexion.movimientosxmqtt;\nconfig_conex.push({ \"parametro\": \"movimientosxmqtt\", \"valor\": read })\nflow.set(\"movimientosxmqtt\", read); // Modo de envio de movimientos\n\nread = config.conexion.movimientosxapi;\nconfig_conex.push({ \"parametro\": \"movimientosxapi\", \"valor\": read })\nflow.set(\"movimientosxapi\", read); // Modo de envio de movimientos\n\n//----------------------------------- DEFINICION DEL BROKER DE MQTT --------------------------------------------------------------------------------------\n/*\nread = config.conexion.broker_url;\nconfig_conex.push({ \"parametro\": \"broker_url\", \"valor\": read })\nflow.set(\"broker_url\", read); // direccion del broker\n\nread = config.conexion.broker_port;\nconfig_conex.push({ \"parametro\": \"broker_port\", \"valor\": read })\nflow.set(\"broker_port\", read); // puerto del broker\n\nread = config.conexion.broker_username;\nconfig_conex.push({ \"parametro\": \"broker_username\", \"valor\": read })\nflow.set(\"broker_username\", read); // username del broker\n\nread = config.conexion.broker_pass;\nconfig_conex.push({ \"parametro\": \"broker_pass\", \"valor\": read })\nflow.set(\"broker_pass\", read); // password del broker\n*/\n/*\n//-------------------------------------------------- URL de la API de URBASER(Trypton) ------------------------------------------------------------------------------\nread = config.conexion.url_API;\nconfig_conex.push({ \"parametro\": \"url_API\", \"valor\": read })\nflow.set(\"url_API\", read); // Modo de funcionamiento del totem\n*/\nflow.set(\"semaforo\", \"green\")\n\n//------------------------------------Lector de QR / RF----------------------------------------------------------\nread = config.sensores.tipo_de_lector\nconfig_sensor.push({ \"parametro\": \"tipo_de_lector\", \"valor\": read })\nflow.set(\"tipo_de_lector\", read); //tipo de lector QR / RF\nread = config.sensores.rfid_invertido\nconfig_sensor.push({ \"parametro\": \"rfid_invertido\", \"valor\": read })\nflow.set(\"rfid_invertido\", read);\nflow.set(\"lector_activo\", true) // activamos el lector\nflow.set(\"ID_enviado\", false) // variable para controlar un solo envio de RFID / QR\n\n//-------------------------------------sensor de distancia-------------------------------------------------------\nread = config.sensores.sensor_distancia_local\nconfig_sensor.push({ \"parametro\": \"sensor_distancia_local\", \"valor\": read })\nflow.set(\"sensor_distancia_local\", read);\nread = config.sensores.sensor_distancia_remoto\nconfig_sensor.push({ \"parametro\": \"sensor_distancia_remoto\", \"valor\": read })\nflow.set(\"sensor_distancia_remoto\", read);\nflow.set(\"distance_flag_remote\", false)\nread = config.sensores.distance_min\nconfig_sensor.push({ \"parametro\": \"distance_min\", \"valor\": read })\nflow.set(\"distance_min\", read);\nread = config.sensores.min_cnt_in_ok\nconfig_sensor.push({ \"parametro\": \"min_cnt_in_ok\", \"valor\": read })\nflow.set(\"min_cnt_in_ok\", read);\nread = config.sensores.min_cnt_out_ok\nconfig_sensor.push({ \"parametro\": \"min_cnt_out_ok\", \"valor\": read })\nflow.set(\"min_cnt_out_ok\", read);\nflow.set(\"dist_in_counter\", 0);\nflow.set(\"dist_out_counter\", 0);\n\n//---------------------------------------Totems y Camara------------------------------------------------------------------------------\nread = config.conexion.totem_qty\nconfig_conex.push({ \"parametro\": \"totem_qty\", \"valor\": read })\nflow.set(\"totem_qty\", read);\nread = config.conexion.totem_id_remoto\nconfig_conex.push({ \"parametro\": \"totem_id_remoto\", \"valor\": read })\nflow.set(\"totem_id_remoto\", read);\nread = config.conexion.totem_id\nconfig_conex.push({ \"parametro\": \"totem_id\", \"valor\": read })\nflow.set(\"totem_id\", read);\nread = config.conexion.numero_vial;\nconfig_conex.push({ \"parametro\": \"numero_vial\", \"valor\": read })\nflow.set(\"numero_vial\", read);\nread = config.conexion.ip_totem_pareja\nconfig_conex.push({ \"parametro\": \"ip_totem_pareja\", \"valor\": read })\nflow.set(\"ip_totem_pareja\", read);\nread = config.camara.camara_matricula\nconfig_camara.push({ \"parametro\": \"camara_matricula\", \"valor\": read })\nflow.set(\"camara_matricula\", read);\nread = config.camara.camaraID\nconfig_camara.push({ \"parametro\": \"camaraID\", \"valor\": read })\nflow.set(\"camaraID\", read);\nread = config.camara.camara_IP\nconfig_camara.push({ \"parametro\": \"camara_IP\", \"valor\": read })\nflow.set(\"camara_IP\", read);\n\n\n//---------------------------------------Lectura de Matricula-----------------------------------------------------------------------\nread = config.tiempos.time_max_2_bascula\nconfig_tiempos.push({ \"parametro\": \"time_max_2_bascula\", \"valor\": read })\nflow.set(\"time_max_2_bascula\", read);\nread = config.tiempos.wait_time_to_send_plate\nconfig_tiempos.push({ \"parametro\": \"wait_time_to_send_plate\", \"valor\": read })\nflow.set(\"wait_time_to_send_plate\", read);\nread = config.tiempos.max_wait_time_to_send_plate\nconfig_tiempos.push({ \"parametro\": \"max_wait_time_to_send_plate\", \"valor\": read })\nflow.set(\"max_wait_time_to_send_plate\", read);\nread = config.tiempos.max_time_bascula_sensor\nconfig_tiempos.push({ \"parametro\": \"max_time_bascula_sensor\", \"valor\": read })\nflow.set(\"max_time_bascula_sensor\", read);\nread = config.tiempos.time_to_snapshot\nconfig_tiempos.push({ \"parametro\": \"time_to_snapshot\", \"valor\": read })\nflow.set(\"time_to_snapshot\", read);\nflow.set(\"plate_sent\", false);\nflow.set(\"anpr0_flag\", false);\n\n//----------------------------------------Flags evento bascula---------------------------------------------------------------------------------------------\nflow.set(\"peso_trigger_OFF\", true);\nflow.set(\"peso_trigger_ON\", false);\n\n//-------------------------------------------------------------------------------------------------------------------------------------\n\nread = config.conexion.supervisor\nconfig_conex.push({ \"parametro\": \"supervisor\", \"valor\": read })\nflow.set(\"supervisor\", read);\n\n//---------------------------------------- Flags edicion de matricula ---------------------------------------------------------------------------------------------\nflow.set(\"badplate\", false) // inicializa flag de solicitu de modificación de matricula\nflow.set(\"prechar\", \"*\") // inicializa variable con caracter de prefijo para el $watch del nodo display de edicion de matricula\n\nflow.set(\"config_general\", config_general)\nflow.set(\"config_tiempos\", config_tiempos)\nflow.set(\"config_mensajes\", config_mensajes)\nflow.set(\"config_conex\", config_conex)\nflow.set(\"config_camara\", config_camara)\nflow.set(\"config_sensor\", config_sensor)\n\nflow.set(\"tiposDatosGlobal\", tiposOriginales) // Pasamos los datos de cada tipo a una variable de flow\n//notese que estos datos son leidos del archivo, sin hacerles transformacion a objeto.\n\n// Vamos a ver si tenemos que aplicar algun tipo de configuracion particular al tipo que se ha seleccionado en la configuracion (Tipo_Configuracion)\nconst tipo = parseInt(config.general.Tipo_Configuracion, 10); // asegura que el numero es integer\n\nif (tipo > 0 && tipo <= 6) {\n const tipoDatos = config.tipos[tipo] || [];\n\n tipoDatos.forEach(item => {\n let valor = item.valor;\n\n if (valor === \"true\") valor = true;\n if (valor === \"false\") valor = false;\n\n flow.set(item.parametro, valor); // sobre escribimos el valor configurado con la configuracion que este definida en el tipo.\n });\n}\n\nreturn;\n\n\n//*********************************************************** FUNCIONES **************************************************/\nfunction toObject(array) {\n const obj = {};\n array.forEach(el => {\n obj[el.parametro] = el.valor;\n });\n return obj;\n}\n", + "func": "const config = JSON.parse(msg.payload);\nmsg ={}; // clear msg object\nlet read;\nlet config_general = []\nlet config_tiempos = []\nlet config_mensajes = []\nlet config_sensor = []\nlet config_camara = []\nlet config_conex = []\nlet config_tipos = []\n\nconfig.general = toObject(config.general);\nconfig.camara = toObject(config.camara);\nconfig.conexion = toObject(config.conexion);\nconfig.sensores = toObject(config.sensores);\nconfig.mensajes = toObject(config.mensajes);\nconfig.tiempos = toObject(config.tiempos);\n\nconst tiposOriginales = config.tipos || {};\n\n\n// Aseguramos que cada tipo esté como array vacío si no tiene nada\nfor (let i = 1; i <= 6; i++) {\n if (!Array.isArray(tiposOriginales[i])) {\n tiposOriginales[i] = [];\n }\n}\nflow.set(\"tiposDatosGlobal\", tiposOriginales);\n\nconfig.tipos = tiposOriginales;\n\n\n\n//**************************** Parametros de Validacion OBLIGATORIOS para PESADA FINALIZADA ***************************************\n// Estos parametros pueden ser: QR / RFID / Boton Validacion / Detector Vehiculo \n//*********************************************************************************************************************************\n/*read = config.QR_obligatorio;\nconfig_general.push({ \"parametro\": \"QR_obligatorio\", \"valor\": read })\nflow.set(\"QR_obligatorio\", read);\nread = config.RFID_obligatorio;\nconfig_general.push({ \"parametro\": \"RFID_obligatorio\", \"valor\": read })\nflow.set(\"RFID_obligatorio\", read);\n\nread = config.general.funcion_totem;\nconfig_general.push({ \"parametro\": \"funcion_totem\", \"valor\": read })\nflow.set(\"funcion_totem\", read);\n\nread = config.general.identificacion_esp;\nconfig_general.push({ \"parametro\": \"identificacion_esp\", \"valor\": read })\nflow.set(\"identificacion_esp\", read);\n\nread = config.tiempos.timer1;\nconfig_tiempos.push({ \"parametro\": \"timer1\", \"valor\": read })\nflow.set(\"timer1\", read);\n\n*/\n\nread = config.general.Tipo_Configuracion;\nconfig_general.push({ \"parametro\": \"Tipo_Configuracion\", \"valor\": read })\nflow.set(\"Tipo_Configuracion\", read);\n\nread = config.general.ID_obligatorio;\nconfig_general.push({ \"parametro\": \"ID_obligatorio\", \"valor\": read })\nflow.set(\"ID_obligatorio\", read);\n\nread = config.general.salida_ID_obligatorio;\nconfig_general.push({ \"parametro\": \"salida_ID_obligatorio\", \"valor\": read })\nflow.set(\"salida_ID_obligatorio\", read);\n\nread = config.general.detector_obligatorio;\nconfig_general.push({ \"parametro\": \"detector_obligatorio\", \"valor\": read })\nflow.set(\"detector_obligatorio\", read);\n\nread = config.general.boton_obligatorio;\nconfig_general.push({ \"parametro\": \"boton_obligatorio\", \"valor\": read })\nflow.set(\"boton_obligatorio\", read);\nread = config.general.firma_obligatoria;\nconfig_general.push({ \"parametro\": \"firma_obligatoria\", \"valor\": read })\nflow.set(\"firma_obligatoria\", read);\nread = config.general.matricula_obligatoria;\nconfig_general.push({ \"parametro\": \"matricula_obligatoria\", \"valor\": read })\nflow.set(\"matricula_obligatoria\", read);\n\n\n\n//==================================================================================================================================\nread = config.general.edicion_matricula;\nconfig_general.push({ \"parametro\": \"edicion_matricula\", \"valor\": read })\nflow.set(\"edicion_matricula\", read); // Habilita la edicion de matricula\n\nread = config.general.botonsalida_activo;\nconfig_general.push({ \"parametro\": \"botonsalida_activo\", \"valor\": read })\nflow.set(\"botonsalida_activo\", read); // Permite poner boton de salida\n\nread = config.general.menu_activo;\nconfig_general.push({ \"parametro\": \"menu_activo\", \"valor\": read })\nflow.set(\"menu_activo\", read); // Permite poner los menus de contratacion\n\n/*\nread = config.general.firma_habilitada;\nconfig_general.push({ \"parametro\": \"firma_habilitada\", \"valor\": read })\nflow.set(\"firma_habilitada\", read); // Habilita la edicion de firma\n*/\n\nread = config.general.barrera_habilitada;\nconfig_general.push({ \"parametro\": \"barrera_habilitada\", \"valor\": read })\nflow.set(\"barrera_habilitada\", read); // Habilita el uso de barrera\n\nread = config.general.mostrar_ubicacion\nconfig_general.push({ \"parametro\": \"mostrar_ubicacion\", \"valor\": read })\nflow.set(\"mostrar_ubicacion\", read);\n\nread = config.general.switch_2_Totem_page;\nflow.set(\"switch_2_Totem_page\", read); // si igual a true cambia a pagina principal del totem siempre que se active la bascula\n// Con esto aseguramos que si queda abierta una ventana de configuracion se pueda quitar automaticamente\nconfig_general.push({ \"parametro\": \"switch_2_Totem_page\", \"valor\": read })\n\n//flow.set(\"peso\", read); // crea variable para recibir peso del supervisor\n\nread = parseInt(config.general.peso_minimo); // peso minimo para utilizado para indicar cuando hay vehiculo en la balanza o no\nconfig_general.push({ \"parametro\": \"peso_minimo\", \"valor\": read })\nflow.set(\"peso_minimo\", read);\n\nread = config.general.formatoPais; // peso minimo para utilizado para indicar cuando hay vehiculo en la balanza o no\nconfig_general.push({ \"parametro\": \"formatoPais\", \"valor\": read })\nflow.set(\"formatoPais\", read);\n\n//------------------- TOTEM MASTER tiempo de confirmacion -------------------------------------\nread = config.tiempos.confirm_master_time;\nconfig_tiempos.push({ \"parametro\": \"confirm_master_time\", \"valor\": read })\nflow.set(\"confirm_master_time\", read);\n//---------------------------------------------------------------------------------------------\n\n\nread = config.general.audio_level;\nconfig_general.push({ \"parametro\": \"audio_level\", \"valor\": read })\nflow.set(\"audio_level\", read);\n//-------------------------------------------------------\nread = config.general.mante_code_RFID; //codigo RFID para pasar a pantalla de mantenimiento\nconfig_general.push({ \"parametro\": \"mante_code_RFID\", \"valor\": read })\nflow.set(\"mante_code_RFID\", read)\nread = config.general.mante_code_QR; //codigo QR para pasar a pantalla de mantenimiento\nconfig_general.push({ \"parametro\": \"mante_code_QR\", \"valor\": read })\nflow.set(\"mante_code_QR\", read)\n\n//------------------------------- MENSAJES -------------------------\nread = config.tiempos.tiempo_mensaje;\nconfig_tiempos.push({ \"parametro\": \"tiempo_mensaje\", \"valor\": read })\nflow.set(\"tiempo_mensaje\", read);\n\nread = config.tiempos.relay2_pulse // duración del pulso generado en el relay 2 al terminar el pesaje para abrir barrera\nconfig_tiempos.push({ \"parametro\": \"relay2_pulse\", \"valor\": read })\nflow.set(\"relay2_pulse\", read);\n\nread = config.mensajes.mensaje2 // no se usa\nconfig_mensajes.push({ \"parametro\": \"mensaje2\", \"valor\": read })\nflow.set(\"mensaje2\", read);\nread = config.mensajes.mensaje1 // no se usa\nconfig_mensajes.push({ \"parametro\": \"mensaje1\", \"valor\": read })\nflow.set(\"mensaje1\", read);\nread = config.general.init_screen\nconfig_general.push({ \"parametro\": \"init_screen\", \"valor\": read })\nflow.set(\"init_screen\", read);\n\n//-------------------------------------------------------\nread = config.general.totem_serial // seriall asignado a este dispositivo\nconfig_general.push({ \"parametro\": \"totem_serial\", \"valor\": read })\nflow.set(\"totem_serial\", read);\n\n//---------------------------------------- Parametros por defecto del boton de salida para VALIDACION -----------------------------------------------------------\nread = config.mensajes.botonsalida_txt_def\nconfig_mensajes.push({ \"parametro\": \"botonsalida_txt_def\", \"valor\": read })\nflow.set(\"botonsalida_txt_def\", read)\nread = config.general.botonsalida_color_def\nconfig_general.push({ \"parametro\": \"botonsalida_color_def\", \"valor\": read })\nflow.set(\"botonsalida_color_def\", read)\nread = config.general.botonsalida_txt_color_def\nconfig_general.push({ \"parametro\": \"botonsalida_txt_color_def\", \"valor\": read })\nflow.set(\"botonsalida_txt_color_def\", read)\nread = config.mensajes.botonsalida_mensaje1\nconfig_mensajes.push({ \"parametro\": \"botonsalida_mensaje1\", \"valor\": read })\nflow.set(\"botonsalida_mensaje1\", read)\nread = config.mensajes.botonsalida_mensaje1_def\nconfig_mensajes.push({ \"parametro\": \"botonsalida_mensaje1_def\", \"valor\": read })\nflow.set(\"botonsalida_mensaje1_def\", read)\n\n//----------------------------------------- Textos Predefinidos -------------------------------------------------------------------------\nread = config.mensajes.men_pesaje_listo;\nconfig_mensajes.push({ \"parametro\": \"men_pesaje_listo\", \"valor\": read })\nflow.set(\"men_pesaje_listo\", read);\nread = config.mensajes.men_peso_estable;\nconfig_mensajes.push({ \"parametro\": \"men_peso_estable\", \"valor\": read })\nflow.set(\"men_peso_estable\", read);\nread = config.mensajes.men_identificacion;\nconfig_mensajes.push({ \"parametro\": \"men_identificacion\", \"valor\": read })\nflow.set(\"men_identificacion\", read);\nread = config.mensajes.men_salida;\nconfig_mensajes.push({ \"parametro\": \"men_salida\", \"valor\": read })\nflow.set(\"men_salida\", read);\nread = config.mensajes.id_titulo_matricula;\nconfig_mensajes.push({ \"parametro\": \"id_titulo_matricula\", \"valor\": read })\nflow.set(\"id_titulo_matricula\", read);\nread = config.mensajes.id_titulo_id;\nconfig_mensajes.push({ \"parametro\": \"id_titulo_id\", \"valor\": read })\nflow.set(\"id_titulo_id\", read);\nread = config.mensajes.id_leido;\nconfig_mensajes.push({ \"parametro\": \"id_leido\", \"valor\": read })\nflow.set(\"id_leido\", read);\nread = config.mensajes.id_no_leido;\nconfig_mensajes.push({ \"parametro\": \"id_no_leido\", \"valor\": read })\nflow.set(\"id_no_leido\", read);\n\n//===================================================CONEXION / CAMARA / SENSOR =====================================================\n//====================================================================================================================================\n\n\nread = config.conexion.modo_totem;\nconfig_conex.push({ \"parametro\": \"modo_totem\", \"valor\": read })\nflow.set(\"modo_totem\", read); // Modo de funcionamiento del totem\n\n\n//-----------------------------Gestion de IP fija / IP DHCP------------------------------------------------------\nvar ipdevice_flag = false // variables temporales para saber si hay cambios en las ip\nvar iprouter_flag = false\nread = config.conexion.ipdevice // direccion IP del dispositivo\nconfig_conex.push({ \"parametro\": \"ipdevice\", \"valor\": read })\nif (flow.get(\"ipdevice\") != read) {\n flow.set(\"ipdevice\", read);\n ipdevice_flag = true;\n}\nread = config.conexion.iprouter // direccion IP del router\nconfig_conex.push({ \"parametro\": \"iprouter\", \"valor\": read })\nif (flow.get(\"iprouter\") != read) {\n flow.set(\"iprouter\", read);\n iprouter_flag = true;\n}\nread = config.conexion.dhcp_flag // flag del DHCP\nconfig_conex.push({ \"parametro\": \"dhcp_flag\", \"valor\": read })\nif (flow.get(\"dhcp_flag\") != read) {\n flow.set(\"dhcp_flag\", read); // el dhcp_flag ha cambiado\n if (flow.get(\"dhcp_flag\")) {\n node.send([null, { payload: \". /home/trypton/scripts/enable_dhcp.sh\" }])\n }\n else {\n node.send([null, { payload: \". /home/trypton/scripts/enable_ipstatic.sh \" + flow.get(\"ipdevice\") + \"/24 \" + flow.get(\"iprouter\") }])\n }\n}\nelse { // el dhcp_flag no ha cambiado\n if (!flow.get(\"dhcp_flag\")) {\n if (ipdevice_flag || iprouter_flag) {\n node.send([null, { payload: \". /home/trypton/scripts/enable_ipstatic.sh \" + flow.get(\"ipdevice\") + \"/24 \" + flow.get(\"iprouter\") }])\n }\n }\n else {\n node.send([null, { payload: \". /home/trypton/scripts/enable_dhcp.sh\" }])\n }\n}\nflow.set(\"dhcpname_on\", \"IP Fija\") // texto que sale en el boton de la pantalla de mantenimiento\nflow.set(\"dhcpname_off\", \"DHCP\")\n//-----------------------------------Websocket IP--------------------------------------------------------------------------------------\nread = config.conexion.websocket_puerto // direccion IP del websocket del supervisor\nconfig_conex.push({ \"parametro\": \"websocket_puerto\", \"valor\": read })\nflow.set(\"websocket_puerto\", read);\nread = config.conexion.websocket_url\nconfig_conex.push({ \"parametro\": \"websocket_url\", \"valor\": read })\nif (flow.get(\"websocket_url\") != read) {\n flow.set(\"websocket_url\", read);\n node.send([{ payload: read + \" servidor.com\" }, null])\n}\n//----------------------------------- ENVIO DE MOVIMIENTOS --------------------------------------------------------------------------------------\nread = config.conexion.movimientosxmqtt;\nconfig_conex.push({ \"parametro\": \"movimientosxmqtt\", \"valor\": read })\nflow.set(\"movimientosxmqtt\", read); // Modo de envio de movimientos\n\nread = config.conexion.movimientosxapi;\nconfig_conex.push({ \"parametro\": \"movimientosxapi\", \"valor\": read })\nflow.set(\"movimientosxapi\", read); // Modo de envio de movimientos\n\n//----------------------------------- DEFINICION DEL BROKER DE MQTT --------------------------------------------------------------------------------------\n/*\nread = config.conexion.broker_url;\nconfig_conex.push({ \"parametro\": \"broker_url\", \"valor\": read })\nflow.set(\"broker_url\", read); // direccion del broker\n\nread = config.conexion.broker_port;\nconfig_conex.push({ \"parametro\": \"broker_port\", \"valor\": read })\nflow.set(\"broker_port\", read); // puerto del broker\n\nread = config.conexion.broker_username;\nconfig_conex.push({ \"parametro\": \"broker_username\", \"valor\": read })\nflow.set(\"broker_username\", read); // username del broker\n\nread = config.conexion.broker_pass;\nconfig_conex.push({ \"parametro\": \"broker_pass\", \"valor\": read })\nflow.set(\"broker_pass\", read); // password del broker\n*/\n/*\n//-------------------------------------------------- URL de la API de URBASER(Trypton) ------------------------------------------------------------------------------\nread = config.conexion.url_API;\nconfig_conex.push({ \"parametro\": \"url_API\", \"valor\": read })\nflow.set(\"url_API\", read); // Modo de funcionamiento del totem\n*/\nflow.set(\"semaforo\", \"green\")\n\n//------------------------------------Lector de QR / RF----------------------------------------------------------\nread = config.sensores.tipo_de_lector\nconfig_sensor.push({ \"parametro\": \"tipo_de_lector\", \"valor\": read })\nflow.set(\"tipo_de_lector\", read); //tipo de lector QR / RF\nread = config.sensores.rfid_invertido\nconfig_sensor.push({ \"parametro\": \"rfid_invertido\", \"valor\": read })\nflow.set(\"rfid_invertido\", read);\nflow.set(\"lector_activo\", true) // activamos el lector\nflow.set(\"ID_enviado\", false) // variable para controlar un solo envio de RFID / QR\n\n//-------------------------------------sensor de distancia-------------------------------------------------------\nread = config.sensores.sensor_distancia_local\nconfig_sensor.push({ \"parametro\": \"sensor_distancia_local\", \"valor\": read })\nflow.set(\"sensor_distancia_local\", read);\nread = config.sensores.sensor_distancia_remoto\nconfig_sensor.push({ \"parametro\": \"sensor_distancia_remoto\", \"valor\": read })\nflow.set(\"sensor_distancia_remoto\", read);\nflow.set(\"distance_flag_remote\", false)\nread = config.sensores.distance_min\nconfig_sensor.push({ \"parametro\": \"distance_min\", \"valor\": read })\nflow.set(\"distance_min\", read);\nread = config.sensores.min_cnt_in_ok\nconfig_sensor.push({ \"parametro\": \"min_cnt_in_ok\", \"valor\": read })\nflow.set(\"min_cnt_in_ok\", read);\nread = config.sensores.min_cnt_out_ok\nconfig_sensor.push({ \"parametro\": \"min_cnt_out_ok\", \"valor\": read })\nflow.set(\"min_cnt_out_ok\", read);\nflow.set(\"dist_in_counter\", 0);\nflow.set(\"dist_out_counter\", 0);\n\n//---------------------------------------Totems y Camara------------------------------------------------------------------------------\nread = config.conexion.totem_qty\nconfig_conex.push({ \"parametro\": \"totem_qty\", \"valor\": read })\nflow.set(\"totem_qty\", read);\nread = config.conexion.totem_id_remoto\nconfig_conex.push({ \"parametro\": \"totem_id_remoto\", \"valor\": read })\nflow.set(\"totem_id_remoto\", read);\nread = config.conexion.totem_id\nconfig_conex.push({ \"parametro\": \"totem_id\", \"valor\": read })\nflow.set(\"totem_id\", read);\nread = config.conexion.numero_vial;\nconfig_conex.push({ \"parametro\": \"numero_vial\", \"valor\": read })\nflow.set(\"numero_vial\", read);\nread = config.conexion.ip_totem_pareja\nconfig_conex.push({ \"parametro\": \"ip_totem_pareja\", \"valor\": read })\nflow.set(\"ip_totem_pareja\", read);\nread = config.camara.camara_matricula\nconfig_camara.push({ \"parametro\": \"camara_matricula\", \"valor\": read })\nflow.set(\"camara_matricula\", read);\nread = config.camara.camaraID\nconfig_camara.push({ \"parametro\": \"camaraID\", \"valor\": read })\nflow.set(\"camaraID\", read);\nread = config.camara.camara_IP\nconfig_camara.push({ \"parametro\": \"camara_IP\", \"valor\": read })\nflow.set(\"camara_IP\", read);\nread = config.camara.camara_contexto\nconfig_camara.push({ \"parametro\": \"camara_contexto\", \"valor\": read })\nflow.set(\"camara_contexto\", read);\nread = config.camara.camara_contexto_IP\nconfig_camara.push({ \"parametro\": \"camara_contexto_IP\", \"valor\": read })\nflow.set(\"camara_contexto_IP\", read);\n\n//---------------------------------------Lectura de Matricula-----------------------------------------------------------------------\nread = config.tiempos.time_max_2_bascula\nconfig_tiempos.push({ \"parametro\": \"time_max_2_bascula\", \"valor\": read })\nflow.set(\"time_max_2_bascula\", read);\nread = config.tiempos.wait_time_to_send_plate\nconfig_tiempos.push({ \"parametro\": \"wait_time_to_send_plate\", \"valor\": read })\nflow.set(\"wait_time_to_send_plate\", read);\nread = config.tiempos.max_wait_time_to_send_plate\nconfig_tiempos.push({ \"parametro\": \"max_wait_time_to_send_plate\", \"valor\": read })\nflow.set(\"max_wait_time_to_send_plate\", read);\nread = config.tiempos.max_time_bascula_sensor\nconfig_tiempos.push({ \"parametro\": \"max_time_bascula_sensor\", \"valor\": read })\nflow.set(\"max_time_bascula_sensor\", read);\nread = config.tiempos.time_to_snapshot\nconfig_tiempos.push({ \"parametro\": \"time_to_snapshot\", \"valor\": read })\nflow.set(\"time_to_snapshot\", read);\nflow.set(\"plate_sent\", false);\nflow.set(\"anpr0_flag\", false);\n\n//----------------------------------------Flags evento bascula---------------------------------------------------------------------------------------------\nflow.set(\"peso_trigger_OFF\", true);\nflow.set(\"peso_trigger_ON\", false);\n\n//-------------------------------------------------------------------------------------------------------------------------------------\n\nread = config.conexion.supervisor\nconfig_conex.push({ \"parametro\": \"supervisor\", \"valor\": read })\nflow.set(\"supervisor\", read);\n\n//---------------------------------------- Flags edicion de matricula ---------------------------------------------------------------------------------------------\nflow.set(\"badplate\", false) // inicializa flag de solicitu de modificación de matricula\nflow.set(\"prechar\", \"*\") // inicializa variable con caracter de prefijo para el $watch del nodo display de edicion de matricula\n\nflow.set(\"config_general\", config_general)\nflow.set(\"config_tiempos\", config_tiempos)\nflow.set(\"config_mensajes\", config_mensajes)\nflow.set(\"config_conex\", config_conex)\nflow.set(\"config_camara\", config_camara)\nflow.set(\"config_sensor\", config_sensor)\n\nflow.set(\"tiposDatosGlobal\", tiposOriginales) // Pasamos los datos de cada tipo a una variable de flow\n//notese que estos datos son leidos del archivo, sin hacerles transformacion a objeto.\n\n// Vamos a ver si tenemos que aplicar algun tipo de configuracion particular al tipo que se ha seleccionado en la configuracion (Tipo_Configuracion)\nconst tipo = parseInt(config.general.Tipo_Configuracion, 10); // asegura que el numero es integer\n\nif (tipo > 0 && tipo <= 6) {\n const tipoDatos = config.tipos[tipo] || [];\n\n tipoDatos.forEach(item => {\n let valor = item.valor;\n\n if (valor === \"true\") valor = true;\n if (valor === \"false\") valor = false;\n\n flow.set(item.parametro, valor); // sobre escribimos el valor configurado con la configuracion que este definida en el tipo.\n });\n}\n\nreturn;\n\n\n//*********************************************************** FUNCIONES **************************************************/\nfunction toObject(array) {\n const obj = {};\n array.forEach(el => {\n obj[el.parametro] = el.valor;\n });\n return obj;\n}\n", "outputs": 2, "timeout": 0, "noerr": 0, @@ -5824,24 +5840,6 @@ "y": 820, "wires": [] }, - { - "id": "eed0d30668b76183", - "type": "debug", - "z": "953e8740401d175c", - "g": "646bdfb9988a1708", - "name": "debug 10", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1980, - "y": 1420, - "wires": [] - }, { "id": "efa47b4b532c3c95", "type": "link out", @@ -5902,17 +5900,17 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 2160, - "y": 1340, + "x": 2260, + "y": 1320, "wires": [] }, { "id": "53335688d117ec96", "type": "comment", "z": "953e8740401d175c", - "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, + "name": "Version 1.4 de bascula autonoma", + "info": "**Version 1.4** \n- Debido a nuevo requerimiento se introduce la opcion (configurable) de tener una camara de contexto en la bascula. Esta camara en caso de estar\nhabilitada en la configuracion tomara una imagen en el momento en que el camion este completamente en la bascula, para ello hemos introducido un codigo en el nodo\n\"estable\" que es donde se hace la deteccion del camion completamente en la bascula. Posteriormente en el nodo \"Analisis del modo de Operacion\" es\ndonde verificamos que la imagen fue tomada y la colocamos en el registro que se esta haciendo para generar el movimiento correspondiente. El Grupo \n\"CAMARA CONTEXTO\" posee los nodos de solicitud de imagen y de recepcion de la misma. La configuracion de IP de la camara se hace en la pantalla\nde configuracion al igual que su habilitacion en el sistema.\n- Como herramienta de ayuda para saber si el Totem esta en capacidad de solicitar y de recibir la imagen de contexto enviada por la camara\nse ha incluido una funcion en el menu de configuracion -> Pruebas del sistema -> Pedir Snapshot de contexto de forma que el usuario pueda visualizar \nla imagen actual que la camara esta enviando y pueda de esa forma confirmar el correcto funcionamiento de la conexión y de los equipos.\n\n**Version 1.3.2** \n- Eliminado la inicializacion en el nodo peso del flag distance_flag_SET del detector de vehiculos. Esto ocasionaba problemas en si \ncoincidia que estaba contando los pulsos de salida y antes de finalizar las bascula se ponia en peso < pmin. En esa situacion el detector\nse quedaba bloqueado in poder indicar detector OFF.\n\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": 1290, "y": 800, "wires": [] }, @@ -5932,7 +5930,7 @@ "className": "", "topic": "", "name": "aviso PMA", - "x": 1310, + "x": 1350, "y": 1160, "wires": [ [ @@ -5968,26 +5966,8 @@ "links": [ "0df0c819dae1658d" ], - "x": 1855, - "y": 1160, - "wires": [] - }, - { - "id": "1210dd76a59df098", - "type": "debug", - "z": "953e8740401d175c", - "g": "646bdfb9988a1708", - "name": "debug 1", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 1940, - "y": 1140, + "x": 1925, + "y": 1100, "wires": [] }, { @@ -6000,7 +5980,7 @@ "links": [ "e0b4dd6107f95f28" ], - "x": 2705, + "x": 2905, "y": 1100, "wires": [] }, @@ -6018,7 +5998,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 2840, + "x": 3040, "y": 1100, "wires": [] }, @@ -6036,7 +6016,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 2560, + "x": 2760, "y": 1000, "wires": [] }, @@ -6472,8 +6452,8 @@ "links": [ "e0b4dd6107f95f28" ], - "x": 1205, - "y": 1200, + "x": 1265, + "y": 1220, "wires": [] }, { @@ -6499,7 +6479,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 1450, + "x": 1490, "y": 1160, "wires": [ [ @@ -6523,8 +6503,8 @@ "className": "", "topic": "", "name": "Ubicacion", - "x": 1800, - "y": 1320, + "x": 1940, + "y": 1220, "wires": [ [] ] @@ -7074,5 +7054,242 @@ "x": 2975, "y": 1640, "wires": [] + }, + { + "id": "c79815b5a79ef60a", + "type": "link out", + "z": "953e8740401d175c", + "g": "9328043d4e9512a9", + "name": "camara_contexto_rq", + "mode": "link", + "links": [ + "9b0761cc102bc028" + ], + "x": 1195, + "y": 1180, + "wires": [] + }, + { + "id": "72071eee550615d7", + "type": "http request", + "z": "953e8740401d175c", + "g": "1b1ee13b380e32b6", + "name": "camara contexto", + "method": "GET", + "ret": "bin", + "paytoqs": "ignore", + "url": "", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "digest", + "senderr": false, + "headers": [], + "x": 1760, + "y": 1380, + "wires": [ + [ + "f5b38e6e811de790", + "730bbe3df0ab62db" + ] + ] + }, + { + "id": "f5b38e6e811de790", + "type": "function", + "z": "953e8740401d175c", + "g": "1b1ee13b380e32b6", + "name": "convert to base64", + "func": "// msg.payload llega como Buffer\nif (Buffer.isBuffer(msg.payload)) {\n msg.payload = msg.payload.toString('base64');\n flow.set(\"last_camara_contexto\", msg.payload)\n flow.set(\"camara_contexto_rx\", true)\n let now = new Date()\n //const nowdate = now.toLocaleString('es-ES', { hour12: false });\n let nowdate = now.toLocaleString(\"sv-SE\").replace(/[- :]/g, \"\")\n if(flow.get(\"tipo_movimiento\") === \"inicial\"){\n flow.set(\"nombre_contexto\", flow.get(\"matricula\") + \"-contexto_i-\" + nowdate + \".jpg\")\n }\n else{\n flow.set(\"nombre_contexto\", flow.get(\"matricula\") + \"-contexto_f-\" + nowdate + \".jpg\")\n }\n}\nreturn {payload:1};", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1970, + "y": 1380, + "wires": [ + [ + "8385582377c91fb6" + ] + ] + }, + { + "id": "9b0761cc102bc028", + "type": "link in", + "z": "953e8740401d175c", + "g": "1b1ee13b380e32b6", + "name": "camara_contexto_url", + "links": [ + "c79815b5a79ef60a" + ], + "x": 1635, + "y": 1380, + "wires": [ + [ + "72071eee550615d7" + ] + ] + }, + { + "id": "8385582377c91fb6", + "type": "link out", + "z": "953e8740401d175c", + "g": "1b1ee13b380e32b6", + "name": "contexto_ok", + "mode": "link", + "links": [ + "31e0432a8e9a2f00" + ], + "x": 2105, + "y": 1380, + "wires": [] + }, + { + "id": "31e0432a8e9a2f00", + "type": "link in", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "contexto_rx", + "links": [ + "8385582377c91fb6" + ], + "x": 1605, + "y": 1060, + "wires": [ + [ + "db3e9975c8f562b6" + ] + ] + }, + { + "id": "f3676f905e4ade55", + "type": "function", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "function 3", + "func": "let msg_camara_contexto = {}\nmsg_camara_contexto.url = `http://${flow.get(\"camara_contexto_IP\")}:8080/cgi-bin/snapshot.cgi?channel=1`\nflow.set(\"camara_contexto_rx\", false) // inicializamos flag de imagen no recibida de la camara de contexto\nnode.send( msg_camara_contexto)\nreturn;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1680, + "y": 1280, + "wires": [ + [ + "72071eee550615d7", + "a0aa0f96fe081912" + ] + ] + }, + { + "id": "730bbe3df0ab62db", + "type": "debug", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1960, + "y": 1320, + "wires": [] + }, + { + "id": "ff3913749bd9e2f3", + "type": "inject", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "1", + "payloadType": "num", + "x": 1650, + "y": 1220, + "wires": [ + [ + "f3676f905e4ade55" + ] + ] + }, + { + "id": "a0aa0f96fe081912", + "type": "debug", + "z": "953e8740401d175c", + "g": "646bdfb9988a1708", + "name": "debug 2", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1860, + "y": 1280, + "wires": [] + }, + { + "id": "ee22e8c1327a7b65", + "type": "http request", + "z": "953e8740401d175c", + "g": "e3bc37824e09b774", + "name": "", + "method": "GET", + "ret": "bin", + "paytoqs": "ignore", + "url": "", + "tls": "", + "persist": false, + "proxy": "", + "insecureHTTPParser": false, + "authType": "digest", + "senderr": false, + "headers": [], + "x": 4370, + "y": 2440, + "wires": [ + [ + "b90652f4011dad39", + "f4c61087c128e20f" + ] + ] + }, + { + "id": "b90652f4011dad39", + "type": "link out", + "z": "953e8740401d175c", + "g": "e3bc37824e09b774", + "name": "cam context", + "mode": "link", + "links": [ + "7058b9e632aa584b" + ], + "x": 4485, + "y": 2440, + "wires": [] } ] \ No newline at end of file diff --git a/bascula_autonoma_1_cred.json b/bascula_autonoma_1_cred.json index 2c991e9..28a3c71 100644 --- a/bascula_autonoma_1_cred.json +++ b/bascula_autonoma_1_cred.json @@ -1,3 +1,11 @@ { - "e49672ad6c84b341": {} + "e49672ad6c84b341": {}, + "72071eee550615d7": { + "user": "admin", + "password": "Trypton#2019" + }, + "ee22e8c1327a7b65": { + "user": "admin", + "password": "Trypton#2019" + } } \ No newline at end of file diff --git a/uibuilder/totem/src/index.css b/uibuilder/totem/src/index.css index e881f2d..127c363 100644 --- a/uibuilder/totem/src/index.css +++ b/uibuilder/totem/src/index.css @@ -60,7 +60,16 @@ h3 { } /* =============================== BOTONES =============================== */ - +.boton{ + padding: 10px; + font-size: 24px; + font-weight: bold; + border: none; + border-radius: 10px; + color: white; + cursor: pointer; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + } .btn { padding: 16px; font-size: 16px; @@ -72,6 +81,14 @@ h3 { box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } +.boton.med { + width: 100%; + margin-top: 8px; + } + .boton.blue, + .boton.azul { + background: #3498db; + } .btn.big { width: 100%; margin-top: 10px; @@ -133,6 +150,10 @@ h3 { background: #DAB957; color: #444; } +.btn.skyblue { + background: skyblue; + color: #444; +} /* =============================== BOTONERAS / GRID =============================== */ diff --git a/uibuilder/totem/src/index.html b/uibuilder/totem/src/index.html index 404d816..16c9413 100644 --- a/uibuilder/totem/src/index.html +++ b/uibuilder/totem/src/index.html @@ -110,8 +110,9 @@
- - + + +
@@ -157,6 +158,23 @@ + +
+
+
+ +

CAMARA CONTEXTO

+
+
+ + +
+
Foto
+ +
----
+ +
+
diff --git a/uibuilder/totem/src/index.js b/uibuilder/totem/src/index.js index 71bfaa5..1091cd0 100644 --- a/uibuilder/totem/src/index.js +++ b/uibuilder/totem/src/index.js @@ -30,6 +30,15 @@ uibuilder.onChange('msg', msg => { } + if (msg.payload && msg.payload.pantalla === 'contexto') { + // Limpiar datos visibles + document.getElementById('camara_contexto').textContent = '---'; + document.getElementById('fecha_contexto').textContent = '----'; + // Mostrar imagen vacía + document.getElementById('foto_contexto').src = ""; + + } + if (msg.payload && msg.payload.pantalla === 'escuchar' && msg.buttons != true) { // Limpiar datos visibles document.getElementById('camara_escuchar').textContent = '---'; @@ -39,7 +48,14 @@ uibuilder.onChange('msg', msg => { // Mostrar imagen vacía document.getElementById('foto_escuchar').src = ""; } - + // nuevo paara camara de contexto + if (msg.hasOwnProperty("picture_contexto")) { + if (msg.context_cam) { + document.getElementById('foto_contexto').src = msg.picture_contexto; + document.getElementById('fecha_contexto').textContent = msg.fecha_contexto || ''; + document.getElementById('camara_contexto').textContent = "Contexto" || '---'; + } + } if (msg.hasOwnProperty("picture")) { //uibuilder.send({ payload: msg.payload.Picture.Plate.PlateNumber, topic: msg.payload.Picture.SnapInfo.DeviceID }); if (msg.snapshot_cam) { @@ -57,7 +73,8 @@ uibuilder.onChange('msg', msg => { const total = msg.snapshot_indexmax || 0; const actual = (msg.snapshot_readindex || 0) + 1; document.getElementById('contador').textContent = `${actual} / ${total}`; - } + } + } else if (msg.payload?.pantalla === 'tipos') {