diff --git a/bascula_autonoma_1.json b/bascula_autonoma_1.json index 6b29a8a..29b1933 100644 --- a/bascula_autonoma_1.json +++ b/bascula_autonoma_1.json @@ -287,9 +287,7 @@ "1b1ee13b380e32b6", "31e0432a8e9a2f00", "f3676f905e4ade55", - "730bbe3df0ab62db", - "ff3913749bd9e2f3", - "a0aa0f96fe081912" + "ff3913749bd9e2f3" ], "x": 134, "y": 893, @@ -628,7 +626,7 @@ "a395ed21d7049d5d", "6ebdceb73c4cfbf0" ], - "x": 1264, + "x": 1324, "y": 1459, "w": 942, "h": 222 @@ -698,12 +696,14 @@ "72071eee550615d7", "f5b38e6e811de790", "9b0761cc102bc028", - "8385582377c91fb6" + "8385582377c91fb6", + "a0aa0f96fe081912", + "730bbe3df0ab62db" ], - "x": 1594, - "y": 1339, - "w": 552, - "h": 82 + "x": 1584, + "y": 1319, + "w": 562, + "h": 122 }, { "id": "3966bb218232f6b3", @@ -2156,6 +2156,7 @@ "id": "0bc82cd2485c7679", "type": "inject", "z": "953e8740401d175c", + "d": true, "g": "6443f177eec330e4", "name": "distance ID1", "props": [ @@ -3978,7 +3979,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Analisis del modo \\n de Operacion", - "func": "//***************************** Selecciona Modo de Operacion **************************************************\nif (!flow.get(\"supervisor\")) {\n if (flow.get(\"peso_estable_flag\")) { //El peso estable se obtiene cuando el vehiculo esta frente al Totem (QR / RFID o sino Detector Local ON o bien pulsar un boton que aparezca en pantalla)\n if (flow.get(\"tipo_movimiento\") == \"final\") {\n flow.set(\"firma_ok_flag\", true) // indicamos que la firma esta hecha, esta no hace falta para la salida\n }\n 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])", + "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\") || flow.get(\"camara_contexto_estado\") === \"ok\" || flow.get(\"camara_contexto_estado\") === \"fail\"\n //Se evalua flow.get(\"camara_contexto_estado\")-> si es \"ok\" significa que se recibio la imagen. Si es \"fail\" significa que se agotaron los dos tiempos de espera de los dos intentos\n //los valores posibles de \"camara_contexto_estado\" son \"idle\", waiting1\", \"waiting2\", \"ok\", \"fail\".\n //idle = no se ha iniciado ninguna solicitud de imagen de contexto. \"waiting1\" = Se inicio la primera solicitud de imagen de contexto. \"waiting2\" = Se inicio la segunda solicitud\n //\"ok\" = imagen de contexto recibida. \"fail\" = se enviaron dos intentos y se esperaron los dos tiempos previstos pero no se recibio imagen de contexto.\n \n // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\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 //******************************** AQUI PONDREMOS EL ANALISIS DE LA RX DE LA IMAGEN DE CONTEXTO ********************************************** */\n \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, @@ -4202,8 +4203,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//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, + "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 (vehiculo_en_posicion)\n// 5. Cuando el usuario acepta el editor de matricula (editor_matricula_ok)\n\n\nconst en_posicion = ((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\"))\n//if (((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\nif ( en_posicion && !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 * PROCESAMIENTO DE LA CAMARA DE CONTEXTO\n * ******************************************************************************************************************************************************************* */\n // Evitar relanzar si ya hay un proceso en curso\n const estadoActual = flow.get(\"camara_contexto_estado\") || \"idle\";\n if (estadoActual === \"waiting_1\" || estadoActual === \"waiting_2\") {\n return null;\n }\n // Limpiar timers viejos por seguridad\n const oldT1 = flow.get(\"camara_contexto_timer1\");\n if (oldT1) clearTimeout(oldT1);\n const oldT2 = flow.get(\"camara_contexto_timer2\");\n if (oldT2) clearTimeout(oldT2);\n\n // Nuevo ciclo\n // La variable reqId permanece dentro de los callbacks (SetTimeout1 y SetTimeout2)\n const reqId = Date.now().toString() + \"_\" + Math.floor(Math.random() * 100000);\n // Inicialización de estado\n flow.set(\"camara_contexto_reqid\", reqId);\n flow.set(\"camara_contexto_estado\", \"waiting_1\");\n flow.set(\"camara_contexto_intento\", 1);\n flow.set(\"camara_contexto_rx\", false);\n flow.set(\"camara_contexto_timer1\", null);\n flow.set(\"camara_contexto_timer2\", null);\n // --------- MENSAJE PARA REQUEST 1 ---------\n let msgHttp1 = RED.util.cloneMessage(msg);\n msgHttp1.contexto_reqid = reqId;\n msgHttp1.contexto_intento = 1;\n msgHttp1.camara_contexto_rq = 1;\n msgHttp1.url = `http://${flow.get(\"camara_contexto_IP\")}/cgi-bin/snapshot.cgi?channel=1`;\n\n\n// ------------------------------------------- TIMEOUT 1 DE LA CAMARA DE CONTEXTO -------------------------------------------------------\n const t1 = setTimeout(() => {\n const reqIdActual = flow.get(\"camara_contexto_reqid\");\n const estado = flow.get(\"camara_contexto_estado\");\n const rx = flow.get(\"camara_contexto_rx\");\n\n // Si este timer ya no corresponde al ciclo actual, ignorar\n if (reqIdActual !== reqId) return;\n\n // Si ya llegó imagen, no hacer nada\n if (estado === \"ok\" || rx === true) return;\n\n // Lanzamos intento 2 en caso que no haya llegado la imagen anterior\n flow.set(\"camara_contexto_estado\", \"waiting_2\");\n flow.set(\"camara_contexto_intento\", 2);\n flow.set(\"camara_contexto_rx\", false);\n\n let retryMsg = {\n _source: \"timeout1_retry\",\n contexto_reqid: reqId,\n contexto_intento: 2,\n camara_contexto_rq: 2,\n url: `http://${flow.get(\"camara_contexto_IP\")}/cgi-bin/snapshot.cgi?channel=1`\n };\n\n // Enviamos solicitud 2 desde el propio timer\n node.send([null, null, null, retryMsg, null]);\n//============================================================= FIN DEL TIMEOUT 1 ==============================================================\n\n// ------------------------------------------- TIMEOUT 2 DE LA CAMARA DE CONTEXTO --------------------------------------------------------------\n const t2 = setTimeout(() => {\n const reqIdActual2 = flow.get(\"camara_contexto_reqid\");\n const estado2 = flow.get(\"camara_contexto_estado\");\n const rx2 = flow.get(\"camara_contexto_rx\");\n\n // Si este timer ya no corresponde al ciclo actual, ignorar\n if (reqIdActual2 !== reqId) return;\n\n // Si ya llegó imagen, no hacer nada\n if (estado2 === \"ok\" || rx2 === true) return;\n\n // Fallo definitivo\n flow.set(\"camara_contexto_estado\", \"fail\");\n flow.set(\"camara_contexto_intento\", 2);\n flow.set(\"camara_contexto_rx\", false);\n flow.set(\"camara_contexto_timer2\", null);\n\n // Si quieres, aquí dejas una traza\n node.warn(\"No se recibió imagen de contexto ni en intento 1 ni en intento 2\");\n\n // Opcional: emitir un mensaje de continuación sin imagen\n node.send([null, {payload:1}, null, null, {\n _source: \"contexto_fail_final\",\n contexto_reqid: reqId,\n camara_contexto_estado: \"fail\"\n }]);\n\n }, flow.get(\"camara_contexto_delay1\"));\n\n flow.set(\"camara_contexto_timer2\", t2);\n\n }, flow.get(\"camara_contexto_delay1\"));\n\n flow.set(\"camara_contexto_timer1\", t1);\n\n // salida 1 -> hacia http request\n // salida 2 -> nada por ahora\n return [null, null, null, msgHttp1, null];\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_rq\", 1) // marcamos primera solicitud de camara de contexto\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 setTimeout(function () { // timer para revisar si recibimos respuesta de la camara de contexto\n if (!flow.get(\"camara_contexto_rx\")) { // Si la imagen de contexto aun no ha sido recibida, solicitamos otra\n msg_camara_contexto.url = `http://${flow.get(\"camara_contexto_IP\")}/cgi-bin/snapshot.cgi?channel=1`\n flow.set(\"camara_contexto_rq\", 2) \n node.send([null, null, null, msg_camara_contexto])\n }\n }, flow.get(\"camara_contexto_delay\"))\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, null, null, null]);", + "outputs": 5, "timeout": 0, "noerr": 0, "initialize": "", @@ -4223,7 +4224,8 @@ ], [ "c79815b5a79ef60a" - ] + ], + [] ] }, { @@ -5786,7 +5788,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);\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", + "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);\nread = config.tiempos.camara_contexto_delay1\nconfig_tiempos.push({ \"parametro\": \"camara_contexto_delay1\", \"valor\": read })\nflow.set(\"camara_contexto_delay1\", read);\nread = config.tiempos.camara_contexto_delay2\nconfig_tiempos.push({ \"parametro\": \"camara_contexto_delay2\", \"valor\": read })\nflow.set(\"camara_contexto_delay2\", 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, @@ -5908,9 +5910,9 @@ "id": "53335688d117ec96", "type": "comment", "z": "953e8740401d175c", - "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, + "name": "Version 1.41 de bascula autonoma", + "info": "**Version 1.41** 1/04/2026\n- Dado que puede darse el caso que la camara de contexto no responda en un determinado momento a la solicitud de imagen, se han introducido unas condiciones para tratar de obtener\nla imagen de contexto en caso de fallo temporal. El metodo resumido es el siguiente: Cuando estamos seguros que el vehiculo esta correctamente posicionado\nen la bascula (peso estable) hacemos una solicitud y marcamos un estado (\"waiting1\"), esperamos por la imagen un tiempo definido en la variable (\"camara_contexto_delay1\") \nencaso de no llegar hacemos una segunda solicitud y marcamos el estado (\"waiting2\") y esperamos por la imagen un tiempo definido en la variable (\"camara_contexto_delay2\").\nMientras tanto el semaforo esta en rojo esperando la imagen de contexto, suponiendo que todo lo demas esta ok. Al cabo del ultimo tiempo, marcamos el nuevo estado\nen funcion de lo sucedido, \"ok\" si recibimos la imagen \"fail\" si no la hemos recibido. En cualquiera de los dos casos el semaforo pasa a verde y se continua con la pesada\nEn caso de no tener imagen de contexto, el nombre de la imagen ira vacio (\"\") al igual que la imagen.\n\n**Version 1.4** 25/03/2026\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": 1300, "y": 800, "wires": [] }, @@ -6711,7 +6713,7 @@ "sendError": false, "encoding": "none", "allProps": false, - "x": 1950, + "x": 2010, "y": 1500, "wires": [ [ @@ -6728,7 +6730,7 @@ "group": "ac875e596615614c", "voice": "", "always": true, - "x": 2120, + "x": 2180, "y": 1560, "wires": [] }, @@ -6745,7 +6747,7 @@ "sendError": false, "encoding": "none", "allProps": false, - "x": 1950, + "x": 2010, "y": 1540, "wires": [ [ @@ -6766,7 +6768,7 @@ "sendError": false, "encoding": "none", "allProps": false, - "x": 1930, + "x": 1990, "y": 1580, "wires": [ [ @@ -6786,7 +6788,7 @@ "sendError": false, "encoding": "none", "allProps": false, - "x": 1930, + "x": 1990, "y": 1620, "wires": [ [ @@ -6827,7 +6829,7 @@ "checkall": "true", "repair": false, "outputs": 4, - "x": 1760, + "x": 1820, "y": 1540, "wires": [ [ @@ -6855,7 +6857,7 @@ "6530f7fdb887dbf1", "fab29e0f6601e531" ], - "x": 1305, + "x": 1365, "y": 1540, "wires": [ [ @@ -6876,7 +6878,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 1430, + "x": 1490, "y": 1540, "wires": [ [ @@ -6897,7 +6899,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 1590, + "x": 1650, "y": 1540, "wires": [ [ @@ -6919,7 +6921,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 1540, + "x": 1600, "y": 1640, "wires": [] }, @@ -6932,7 +6934,7 @@ "scope": [ "23706ca448e439ea" ], - "x": 1370, + "x": 1430, "y": 1640, "wires": [ [ @@ -7087,7 +7089,7 @@ "senderr": false, "headers": [], "x": 1760, - "y": 1380, + "y": 1360, "wires": [ [ "f5b38e6e811de790", @@ -7101,7 +7103,7 @@ "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};", + "func": "const reqIdActual = flow.get(\"camara_contexto_reqid\");\nconst estado = flow.get(\"camara_contexto_estado\") || \"idle\";\nconst reqIdMsg = msg.contexto_reqid;\n// Ignorar respuestas viejas o fuera de contexto\nif (reqIdMsg && reqIdMsg !== reqIdActual) {\n node.warn(\"Respuesta de contexto ignorada por reqId antiguo\");\n return null;\n}\n// Si ya estaba resuelto, ignoramos duplicados\nif (estado === \"ok\" || estado === \"fail\") {\n return null;\n}\n\n// Validar contenido recibido\nlet imagenB64 = \"\";\n\nif (Buffer.isBuffer(msg.payload)) {\n imagenB64 = msg.payload.toString(\"base64\");\n} else if (typeof msg.payload === \"string\") {\n imagenB64 = msg.payload;\n} else {\n node.warn(\"La respuesta de la cámara no contiene imagen válida\");\n return null;\n}\n\n// Guardar resultado exitoso\nflow.set(\"last_camara_contexto\", imagenB64);\nflow.set(\"camara_contexto_rx\", true);\nflow.set(\"camara_contexto_estado\", \"ok\");\n\n//Generamos nombre del archivo de la imagen recibida\nlet now = new Date()\nlet nowdate = now.toLocaleString(\"sv-SE\").replace(/[- :]/g, \"\")\nif (flow.get(\"tipo_movimiento\") === \"inicial\") {\n flow.set(\"nombre_contexto\", flow.get(\"matricula\") + \"-contexto_i-\" + nowdate + \".jpg\")\n}\nelse {\n flow.set(\"nombre_contexto\", flow.get(\"matricula\") + \"-contexto_f-\" + nowdate + \".jpg\")\n}\n\n// Cancelar timers pendientes\nconst t1 = flow.get(\"camara_contexto_timer1\");\nif (t1) clearTimeout(t1);\nconst t2 = flow.get(\"camara_contexto_timer2\");\nif (t2) clearTimeout(t2);\nflow.set(\"camara_contexto_timer1\", null);\nflow.set(\"camara_contexto_timer2\", null);\n\nmsg.camara_contexto_estado = \"ok\";\n\nreturn { payload: 1 };\n\n\n/*\n\n// 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};\n*/", "outputs": 1, "timeout": 0, "noerr": 0, @@ -7109,7 +7111,7 @@ "finalize": "", "libs": [], "x": 1970, - "y": 1380, + "y": 1360, "wires": [ [ "8385582377c91fb6" @@ -7125,10 +7127,11 @@ "links": [ "c79815b5a79ef60a" ], - "x": 1635, - "y": 1380, + "x": 1625, + "y": 1360, "wires": [ [ + "a0aa0f96fe081912", "72071eee550615d7" ] ] @@ -7144,7 +7147,7 @@ "31e0432a8e9a2f00" ], "x": 2105, - "y": 1380, + "y": 1360, "wires": [] }, { @@ -7170,7 +7173,7 @@ "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;", + "func": "let msg_camara_contexto = {}\nmsg_camara_contexto.url = `http://${flow.get(\"camara_contexto_IP\")}/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, @@ -7181,8 +7184,7 @@ "y": 1280, "wires": [ [ - "72071eee550615d7", - "a0aa0f96fe081912" + "72071eee550615d7" ] ] }, @@ -7190,7 +7192,7 @@ "id": "730bbe3df0ab62db", "type": "debug", "z": "953e8740401d175c", - "g": "646bdfb9988a1708", + "g": "1b1ee13b380e32b6", "name": "debug 1", "active": true, "tosidebar": true, @@ -7200,8 +7202,8 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 1960, - "y": 1320, + "x": 1940, + "y": 1400, "wires": [] }, { @@ -7238,7 +7240,7 @@ "id": "a0aa0f96fe081912", "type": "debug", "z": "953e8740401d175c", - "g": "646bdfb9988a1708", + "g": "1b1ee13b380e32b6", "name": "debug 2", "active": true, "tosidebar": true, @@ -7248,8 +7250,8 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 1860, - "y": 1280, + "x": 1740, + "y": 1400, "wires": [] }, {