diff --git a/bascula_autonoma_1.json b/bascula_autonoma_1.json index 648605f..01fc6cb 100644 --- a/bascula_autonoma_1.json +++ b/bascula_autonoma_1.json @@ -2659,7 +2659,7 @@ "z": "953e8740401d175c", "g": "0e2b148022a7af13", "name": "analisis detector 2", - "func": "/* Cuando se acerca un vehiculo a la bascula, la camara por lo general envia snapshots con matricula detectada. Estos snapshots los llamamos ANPR0\n y se guarda el ultimo en memoria. Esto sucede antes que el vehiculo active el detector o la bascula.\n - Al momento de activar el detector se solicita un snapshot. Este snapshot recibido sera procesado por el nodo de analisis de la camara\n - En caso de no llegar el snaphot en el tiempo previsto (\"max_wait_time_to_send_plate\") o de recibir el sanpshot fuera de formato entonces se revisa si tenemos\n anpr0 valido y lo enviamos, en caso contrario enviamos una matricula \"NOT FOUND\"\n \n * ANPR0 valido significa que la matricula tiene el formato esperado\n * ANPR0 No valido significa que tiene matricula pero el formato no es correcto (mala lectura)\n \n Definicion de variables importantes:\n anpr0_time = timesatmp al momento de recibir el ANPR0\n anpr0_flag = Si true, hemos recibido al menos un ANPR0\n anpr0_valid_flag = Si true, hemos recibido un ANPR0 con matricula valida\n time_max_2_bascula = tiempo transcurrido desde recepcion del ANPR0 hasta la activacion de la bascula\n wait_time_to_send_plate = tiempo de espera para enviar la matricula, por si llega un nuevo snapshot antes de 3s\n max_wait_time_to_send_plate = tiempo de espera para enviar la matricula, por si llega un nuevo snapshot antes de 10s\n max_time_bascula_sensor = tiempo maximo permitido entre activacion de bascula y activacion del detector de vehiculos\n snapshot_rq_flag = Si true, indica que hemos solicitado un snapshot\n distance_flag = Si true, indica que un vehiculo ha activado el detector\n distance_flag_ONtime = timestamp del momento en que se activo el detector\n last_time_on_off_distance = Tiempo transcurrido entre el ON y el OFF del detector de vehiculos, de la pesada anterior.\n peso_min_time = timestamp del momento en que se activa la bascula. Este se pone a cero cuando detectamos peso < pmin\n \n \n*/\n// Si entra aqui es que se recibio un mensaje del nodo detector remoto\nvar timestamp_now = new Date().getTime()\nvar thisdate = new Date()\nvar msg_rq = {}\nflow.set(\"timestamp_now\", timestamp_now)\n\n//-------------------------------------------------- Caso activacion por el detector de vehiculos ---------------------------------------------\n//Este detector lo usamos aqui en caso de tener 2 Totems, sino el sensor se usa cuando se active la bascula como un estado, en ese caso no pasaria por aqui. \n//En caso de usar la bascula como evento, el resultado del detector no se usaria como evento sino como estado y seria el detector local no el detector remoto\n//En este apartado se atiende el caso de 2T 1SL 1SR asi como 2T 0SL 1SR\n\nif (msg.topic == \"detector_ON\" && flow.get(\"totem_qty\") == 2){ //\"detector_ON\" es lo que envia en el topic del mensaje el detector remoto, cuando detecta vehiculo.\n // hemos recibido un trigger del sensor detector de objetos\n if(flow.get(\"input_flag\")){\n \n // *******solicitud de un snapshot con un delay********\n flow.set(\"disparo\", setTimeout(function(){\n var msg_rq = {}\n flow.set(\"timestamp_rq\", new Date().getTime()) // marcamos tiempo de solicitud\n msg_rq.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n flow.set(\"snapshot_rq_flag\", true) // marcamos que hemos solicitado un snapshot\n node.send([null, msg_rq])\n }, flow.get(\"time_to_snapshot\")));// esperamos un tiempo variable por configuracion entre que recibimos el detector y cuando pedimos el snaphot\n \n \n // ************************************ TIME OUT *********************************************\n flow.set(\"timer_snapshot\", setTimeout(function () { // hacemos una espera hasta que este dentro de la bascula\n //node.warn(\"ts3 = \" + new Date().getTime() + \"time_sensor_to_this = \" + (new Date().getTime() -flow.get(\"distance_flag_ONtime\")))\n var anpr0_2_bascula = flow.get(\"peso_min_time\") - flow.get(\"anpr0_time\") // tiempo entre anpr0 y activacion de bascula\n if(flow.get(\"anpr0_flag\") && ( anpr0_2_bascula < flow.get(\"time_max_2_bascula\") + flow.get(\"max_wait_time_to_send_plate\")) && anpr0_2_bascula >= 0){ // chequea si hay anpr0\n flow.set(\"last_plate\", flow.get(\"anpr0\")) // asignamos anpr0 al objeto que se va a enviar\n \n }\n else{// Si no hay vehiculo identificado enviamos indicacion de que paso un vehiculo sin poder ser identificado\n var plate = {payload:{Picture:{Plate:{}, SnapInfo:{}, NormalPic:{}}}} // construimos parametros para poder procesar estructura de snapshot al enviar la matricula\n plate.payload.Picture.Plate.PlateNumber = \"NOT FOUND\"\n plate.payload.Picture.SnapInfo.SnapTime = thisdate.toLocaleString('es-ES')\n plate.payload.Picture.SnapInfo.DeviceID = flow.get(\"camaraID\")\n plate.payload.Picture.NormalPic.Content = \"\"\n plate.payload.Picture.NormalPic.PicName = \"No Picture\"\n flow.set(\"last_plate\", plate)\n //esto deja constancia de que paso un vehiculo sin poder ver la matricula\n }\n if (!flow.get(\"plate_sent\") && flow.get(\"peso_min_time\") > 0) {//asegurar que hay vehiculo en la bascula\n \n flow.set(\"called_from\", \"2T 1SR snapshot\")\n node.send([{payload:1}, null])\n }\n \n }, flow.get(\"max_wait_time_to_send_plate\")));\n }\n}\nreturn ;", + "func": "/* Cuando se acerca un vehiculo a la bascula, la camara por lo general envia snapshots con matricula detectada. Estos snapshots los llamamos ANPR0\n y se guarda el ultimo en memoria. Esto sucede antes que el vehiculo active el detector o la bascula.\n - Al momento de activar el detector se solicita un snapshot. Este snapshot recibido sera procesado por el nodo de analisis de la camara\n - En caso de no llegar el snaphot en el tiempo previsto (\"max_wait_time_to_send_plate\") o de recibir el sanpshot fuera de formato entonces se revisa si tenemos\n anpr0 valido y lo enviamos, en caso contrario enviamos una matricula \"NOT FOUND\"\n \n * ANPR0 valido significa que la matricula tiene el formato esperado\n * ANPR0 No valido significa que tiene matricula pero el formato no es correcto (mala lectura)\n \n Definicion de variables importantes:\n anpr0_time = timesatmp al momento de recibir el ANPR0\n anpr0_flag = Si true, hemos recibido al menos un ANPR0\n anpr0_valid_flag = Si true, hemos recibido un ANPR0 con matricula valida\n time_max_2_bascula = tiempo transcurrido desde recepcion del ANPR0 hasta la activacion de la bascula\n wait_time_to_send_plate = tiempo de espera para enviar la matricula, por si llega un nuevo snapshot antes de 3s\n max_wait_time_to_send_plate = tiempo de espera para enviar la matricula, por si llega un nuevo snapshot antes de 10s\n max_time_bascula_sensor = tiempo maximo permitido entre activacion de bascula y activacion del detector de vehiculos\n snapshot_rq_flag = Si true, indica que hemos solicitado un snapshot\n distance_flag = Si true, indica que un vehiculo ha activado el detector\n distance_flag_ONtime = timestamp del momento en que se activo el detector\n last_time_on_off_distance = Tiempo transcurrido entre el ON y el OFF del detector de vehiculos, de la pesada anterior.\n peso_min_time = timestamp del momento en que se activa la bascula. Este se pone a cero cuando detectamos peso < pmin\n \n \n*/\n// Si entra aqui es que se recibio un mensaje del nodo detector remoto\nvar timestamp_now = new Date().getTime()\nvar thisdate = new Date()\nvar msg_rq = {}\nflow.set(\"timestamp_now\", timestamp_now)\n\n//-------------------------------------------------- Caso activacion por el detector de vehiculos ---------------------------------------------\n//Este detector lo usamos aqui en caso de tener 2 Totems, sino el sensor se usa cuando se active la bascula como un estado, en ese caso no pasaria por aqui. \n//En caso de usar la bascula como evento, el resultado del detector no se usaria como evento sino como estado y seria el detector local no el detector remoto\n//En este apartado se atiende el caso de 2T 1SL 1SR asi como 2T 0SL 1SR\n\nif (msg.topic == \"detector_ON\" && flow.get(\"totem_qty\") == 2){ //\"detector_ON\" es lo que envia en el topic del mensaje el detector remoto, cuando detecta vehiculo.\n // hemos recibido un trigger del sensor detector de objetos\n if(flow.get(\"input_flag\")){ //Este flag nos indica si el vehiculo esta entrando en la bascual respecto a la posicion del sensor remoto.\n \n // *******solicitud de un snapshot con un delay********\n flow.set(\"disparo\", setTimeout(function(){\n var msg_rq = {}\n flow.set(\"timestamp_rq\", new Date().getTime()) // marcamos tiempo de solicitud\n msg_rq.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n flow.set(\"snapshot_rq_flag\", true) // marcamos que hemos solicitado un snapshot\n node.send([null, msg_rq])\n }, flow.get(\"time_to_snapshot\")));// esperamos un tiempo variable por configuracion entre que recibimos el detector y cuando pedimos el snaphot\n \n \n // ************************************ TIME OUT *********************************************\n flow.set(\"timer_snapshot\", setTimeout(function () { // hacemos una espera hasta que este dentro de la bascula\n //node.warn(\"ts3 = \" + new Date().getTime() + \"time_sensor_to_this = \" + (new Date().getTime() -flow.get(\"distance_flag_ONtime\")))\n var anpr0_2_bascula = flow.get(\"peso_min_time\") - flow.get(\"anpr0_time\") // tiempo entre anpr0 y activacion de bascula\n if(flow.get(\"anpr0_flag\") && ( anpr0_2_bascula < flow.get(\"time_max_2_bascula\") + flow.get(\"max_wait_time_to_send_plate\")) && anpr0_2_bascula >= 0){ // chequea si hay anpr0\n flow.set(\"last_plate\", flow.get(\"anpr0\")) // asignamos anpr0 al objeto que se va a enviar\n \n }\n else{// Si no hay vehiculo identificado enviamos indicacion de que paso un vehiculo sin poder ser identificado\n var plate = {payload:{Picture:{Plate:{}, SnapInfo:{}, NormalPic:{}}}} // construimos parametros para poder procesar estructura de snapshot al enviar la matricula\n plate.payload.Picture.Plate.PlateNumber = \"NOT FOUND\"\n plate.payload.Picture.SnapInfo.SnapTime = thisdate.toLocaleString('es-ES')\n plate.payload.Picture.SnapInfo.DeviceID = flow.get(\"camaraID\")\n plate.payload.Picture.NormalPic.Content = \"\"\n plate.payload.Picture.NormalPic.PicName = \"No Picture\"\n flow.set(\"last_plate\", plate)\n //esto deja constancia de que paso un vehiculo sin poder ver la matricula\n }\n if (!flow.get(\"plate_sent\") && flow.get(\"peso_min_time\") > 0) {//asegurar que hay vehiculo en la bascula\n \n flow.set(\"called_from\", \"2T 1SR snapshot\")\n node.send([{payload:1}, null])\n }\n \n }, flow.get(\"max_wait_time_to_send_plate\")));\n }\n}\nreturn ;", "outputs": 2, "timeout": "", "noerr": 0, @@ -2673,7 +2673,8 @@ "92309a9f0b0f2c29" ], [ - "e49672ad6c84b341" + "e49672ad6c84b341", + "5f429631b4d39e9d" ] ] }, @@ -2727,7 +2728,7 @@ "targetType": "full", "statusVal": "", "statusType": "auto", - "x": 4060, + "x": 4100, "y": 1740, "wires": [] }, @@ -4180,7 +4181,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Peso", - "func": "let peso = flow.get(\"peso\") || 0;\nconst peso_minimo = flow.get(\"peso_minimo\");\nlet peso_estable = flow.get(\"peso_estable\");\nlet semaforo = flow.get(\"semaforo\");\n\nif (peso < peso_minimo) {\n // evento de bascula OFF para cuando el totem no dispone de sensor remoto\n /* eliminamos este trigger para el evento de la bascula\n if (peso < (peso_minimo * 0.8) && flow.get(\"peso_trigger_ON\")) {// consideramos una histeresis\n flow.set(\"peso_trigger_ON\", false) // marcamos que el trigger ON esta en FALSE para proxima activacion de la bascula\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, null])\n }\n */\n //============================================ AQUI SE HACE EL REGISTRO DEL MOVIMIENTO EN BD ===============================\n if(!flow.get(\"peso_bajo_flag\")){ // Se cumple solo una vez al vaciar la bascula\n /* if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")){ \n let date = new Date();\n let timestamp = parseInt(date.getTime()/1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n \n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n \n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")){ // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n //let msg_plate = { payload: flow.get(\"matricula_image\"), filename: flow.get(\"path_images\") + flow.get(\"nombre_imagen\") } // guardamos archivo con imagen en disco local\n \n //flow.set(\"register2API\", new_register) // guardamos el objeto json completo con imagen de matricula e imagen de firma \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 //**************************************************************************************************************************\n\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, msg_mov]) // envio del registro a BD y a la API y envio de evento bascula OFF\n\n flow.set(\"registro\", \"\") // inicializamos el registro para evitar cualquier posible duplicado en bd\n\n }\n */\n flow.set(\"matricula_image\", \"\") // inicializamos imagen del vehiculo\n flow.set(\"plate_sent\", false)\n flow.set(\"matricula_revisada\", false)\n flow.set(\"matricula_autorizada\", false)\n flow.set(\"last_firma\", \"\") // inicializamos imagen de la firma\n flow.set(\"identificacion_pendiente\", false) // estas cuatro lineas son relativas a la identificacion especial para cuando no se puede leer la matricula\n flow.set(\"identificacion_esp_aplicada\", false) // indica que la matricula no fue bien leida y se aplico el parametro de identificacion especial\n flow.set(\"QR_revisado\", false)\n flow.set(\"RFID_revisado\", false)\n flow.set(\"QR_verificado\", false)\n flow.set(\"RFID_verificado\", false)\n flow.set(\"peso_bajo_flag\", true)\n flow.set(\"matricula_leida_flag\", false)\n flow.set(\"matricula_formato_flag\", false)\n flow.set(\"snapshot_rq_flag\", false)\n flow.set(\"lista_array\", [])\n flow.set(\"menu0\", [])\n flow.set(\"menu1\", [])\n flow.set(\"menu2\", [])\n flow.set(\"menu_seleccionado_flag\", false)// indicador de que el usuario termino la seleccion en el menu y se envio\n flow.set(\"id_seleccionado\", \"no recibido\")\n flow.set(\"startmenu_flag\", false) // reset del flag que permite mostrar el boton (\"completar informacion\") de acceso al menu de materiales\n flow.set(\"editor_matricula_ok\", false) // se activa cuando el usuario hace clik en OK para ir a editar la matricula\n flow.set(\"badplate_llamado\", false) // se activa cuando se saca por primera vez la notificacion para EDITRA MATRICULA en la siguiente pantalla\n flow.set(\"nota_modifique_matricula_done\", false) // nota al usuario cuando hay que modificar matricula no registrada\n flow.set(\"nota_vuelva_intentar_done\", false) // nota al usuario despues de corregir la matricula en caso de error\n flow.set(\"nota_avise_basculista_done\", false) // nota al usuario de aviso al basculista\n flow.set(\"nota_resumen_mostrada\", false) // indica que la nota de resumen luego de presentar identificacion ya se mostro (nodo QR / RFID)\n flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n flow.set(\"badplate\", false)\n flow.set(\"semaforoabierto\", true) // flag para gestion del semaforo desde websocket\n //Atributos del vehiculo, leidos de la BD al momento de revisar si la matricula existe en BD\n flow.set(\"pma\", 0)\n flow.set(\"tara\", 0)\n flow.set(\"tipo_movimiento\", \"nodefinido\")\n flow.set(\"register\", {})\n flow.set(\"movimiento_enviado\", false)\n flow.set(\"matriculacheck_solicitada\", false) // flag utilizado para no repetir el envio de la revision de matricula en el nodo Matricula\n \n if (flow.get(\"switch_2_Totem_page\")) { //En caso que este flag haya sido habilitado en configuracion \n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta y cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n \n node.send([null, null, null, null, null, { payload: \"\" }, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n else {\n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta\n node.send([null, null, null, null, null, { payload: \"\" }, null, null]);\n }\n }\n //==========================================================================================================================\n flow.set(\"peso_estable_flag\", false)\n flow.set(\"peso_estable_audio_flag\", true)\n flow.set(\"peso_estable\", 0)\n flow.set(\"fin_pesada_flag\", false)\n //flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n if (flow.get(\"totem_qty\") == 1) { flow.set(\"totem_master\", true) } // en el caso de un solo totem. Este dispositivo siempre sera el master\n flow.set(\"firma_activa\", false)\n flow.set(\"QR_ok_flag\", false);\n flow.set(\"RFID_ok_flag\", false);\n flow.set(\"last_QR\", \"-\")\n flow.set(\"last_RFID\", \"-\")\n flow.set(\"botonsalida\", false)\n flow.set(\"vehiculo_en_posicion\", false)\n flow.set(\"salida_valida_flag\", false)\n flow.set(\"distance_flag_SET\", false)\n flow.set(\"aviso_pma_hecho\", false) // reset del flag indicador de PMA\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"matricula_editada_flag\", false)\n //flow.set(\"matricula\", \"Sin Matricula\")\n //flow.set(\"snapshot_rq_flag\", false)\n //flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n //flow.set(\"badplate\", false)\n flow.set(\"firma_ok_flag\", false)\n flow.set(\"movimiento_registrado_flag\", false)\n if (flow.get((\"semaforoabierto\"))){ // si el semaforo ha sido manipulado desde websocket entonces no lo tocamos\n flow.set(\"semaforo\", \"green\")\n }\n flow.set(\"window_men_m1\", \"\"); // borra posibles mensajes en pantalla \n flow.set(\"window_men_m2\", \"\"); \n flow.set(\"window_men_m3\", \"\");\n flow.set(\"window_id_m4\", \"\");\n flow.set(\"window_id_m2\", \"\");\n \n \n}\nelse {// ************************ peso > pmin *****************************************\n if (flow.get(\"peso_bajo_flag\")) {\n flow.set(\"peso_min_time\", new Date().getTime()) // marca momento en que se detecta peso > peso min\n //node.warn(\"peso_min_time = \" + flow.get(\"peso_min_time\"))\n flow.set(\"horaentrada\", new Date(flow.get(\"peso_min_time\")).toLocaleString()) // Convierte a formato legible\n // evento de bascula ON para cuando hay un solo Totem en la bascula (sin sensor remoto)\n /*\n if (flow.get(\"peso_trigger_ON\") == false) {\n flow.set(\"peso_trigger_ON\", true) // \n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null])\n }\n */\n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null]) // sacamos evento de bascula ON cuando no hay sensor remoto\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"badplate\", false) // inicializamos flag en caso que haya sido enviado cuando peso < pmin \n flow.set(\"vehiculo_presente_flag\", true);\n flow.set(\"ID_enviado\", false) // activamos flag para envio de un unico RFID / QR con peso > pmin\n flow.set(\"esperando_id\", true)\n flow.set(\"peso_bajo_flag\", false);\n\n flow.set(\"semaforo\", \"red\")\n node.send([{ payload: 1 }, null, null, null, null, null, null, null]) // generamos un nuevo UUID\n setTimeout(function () {\n let new_register = {\n uuid: flow.get(\"new_uuid\"),\n horaentrada: flow.get(\"horaentrada\"),\n vial: flow.get(\"numero_vial\"),\n totem: flow.get(\"totem_id\"),\n sincro: false,\n modo: flow.get(\"modo_totem\"),\n firmaobligatoria: flow.get(\"firma_obligatoria\"),\n id_seleccionado: \"no recibido\",\n nombre_firma: \"No Habilitada\",\n QR: \"-\",\n RFID: \"-\",\n matricula: \"Sin Matricula\",\n nombre_imagen: \"Sin Matricula\",\n sentido: \"No conocido\"\n }\n flow.set(\"register\", new_register)\n }, 1000)\n\n if (flow.get(\"switch_2_Totem_page\")) { // si ha sido habilitado cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n node.send([null, null, null, null, null, null, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n \n if ((flow.get(\"modo_totem\") == \"C\" || flow.get(\"modo_totem\") == \"D\" ) && !flow.get(\"supervisor\")){\n if(flow.get(\"botonsalida_activo\")){\n flow.set(\"botonsalida\", true)\n }\n }\n }\n if (flow.get(\"peso_estable_flag\")) {\n flow.set(\"peso\", flow.get(\"peso_estable\"));\n } \n\n \n //-------------------------------procesamiento de la lista de materiales-----------------------------------------------------\n //if (flow.get(\"lista_flag\") && flow.get(\"supervisor\")) {\n if (flow.get(\"lista_flag\")) {\n flow.set(\"lista_flag\", false) // evita otra entrada a esta secuencia para esta misma lista\n var lista = flow.get(\"lista_array\") // lista con todos los materiales y niveles juntos\n const lista_size = flow.get(\"lista_array\").length\n let j = 0; let k = 0; let i = 0; let maxlevel = 0;\n for (i = 0; i < lista_size; i++) { // calculamos el nivel maximo que tiene esta lista de menu\n if (parseInt(lista[i].nivel) > maxlevel) {\n maxlevel = parseInt(lista[i].nivel)\n }\n }\n flow.set(\"maxlevel\", maxlevel + 1) // guardamos el maximo nivel de menu identificado en la lista\n flow.set(\"selections\", \"\") //inicializamos con ninguna seleccion\n if (flow.get(\"menu_inicio\")) {\n flow.set(\"startmenu_flag\", true)\n }\n\n }\n\n //----------------------------------- FIN Lista de Materiales -----------------------------------------------------------------------\n}\n\nreturn ([null, null, null, null, msg, null, null, null]);\n", + "func": "let peso = flow.get(\"peso\") || 0;\nconst peso_minimo = flow.get(\"peso_minimo\");\nlet peso_estable = flow.get(\"peso_estable\");\nlet semaforo = flow.get(\"semaforo\");\n\nif (peso < peso_minimo) {\n // evento de bascula OFF para cuando el totem no dispone de sensor remoto\n /* eliminamos este trigger para el evento de la bascula\n if (peso < (peso_minimo * 0.8) && flow.get(\"peso_trigger_ON\")) {// consideramos una histeresis\n flow.set(\"peso_trigger_ON\", false) // marcamos que el trigger ON esta en FALSE para proxima activacion de la bascula\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, null])\n }\n */\n //============================================ AQUI SE HACE EL REGISTRO DEL MOVIMIENTO EN BD ===============================\n if(!flow.get(\"peso_bajo_flag\")){ // Se cumple solo una vez al vaciar la bascula\n /* if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")){ \n let date = new Date();\n let timestamp = parseInt(date.getTime()/1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n \n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n \n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")){ // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n //let msg_plate = { payload: flow.get(\"matricula_image\"), filename: flow.get(\"path_images\") + flow.get(\"nombre_imagen\") } // guardamos archivo con imagen en disco local\n \n //flow.set(\"register2API\", new_register) // guardamos el objeto json completo con imagen de matricula e imagen de firma \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 //**************************************************************************************************************************\n\n node.send([null, null, null, { payload: 1, topic: \"peso_OFF\" }, null, null, null, msg_mov]) // envio del registro a BD y a la API y envio de evento bascula OFF\n\n flow.set(\"registro\", \"\") // inicializamos el registro para evitar cualquier posible duplicado en bd\n\n }\n */\n flow.set(\"matricula_image\", \"\") // inicializamos imagen del vehiculo\n flow.set(\"plate_sent\", false)\n flow.set(\"matricula_revisada\", false)\n flow.set(\"matricula_autorizada\", false)\n flow.set(\"last_firma\", \"\") // inicializamos imagen de la firma\n flow.set(\"identificacion_pendiente\", false) // estas cuatro lineas son relativas a la identificacion especial para cuando no se puede leer la matricula\n flow.set(\"identificacion_esp_aplicada\", false) // indica que la matricula no fue bien leida y se aplico el parametro de identificacion especial\n flow.set(\"QR_revisado\", false)\n flow.set(\"RFID_revisado\", false)\n flow.set(\"QR_verificado\", false)\n flow.set(\"RFID_verificado\", false)\n flow.set(\"peso_bajo_flag\", true)\n flow.set(\"matricula_leida_flag\", false)\n flow.set(\"matricula_formato_flag\", false)\n flow.set(\"snapshot_rq_flag\", false)\n flow.set(\"lista_array\", [])\n flow.set(\"menu0\", [])\n flow.set(\"menu1\", [])\n flow.set(\"menu2\", [])\n flow.set(\"menu_seleccionado_flag\", false)// indicador de que el usuario termino la seleccion en el menu y se envio\n flow.set(\"id_seleccionado\", \"no recibido\")\n flow.set(\"startmenu_flag\", false) // reset del flag que permite mostrar el boton (\"completar informacion\") de acceso al menu de materiales\n flow.set(\"editor_matricula_ok\", false) // se activa cuando el usuario hace clik en OK para ir a editar la matricula\n flow.set(\"badplate_llamado\", false) // se activa cuando se saca por primera vez la notificacion para EDITRA MATRICULA en la siguiente pantalla\n flow.set(\"nota_modifique_matricula_done\", false) // nota al usuario cuando hay que modificar matricula no registrada\n flow.set(\"nota_vuelva_intentar_done\", false) // nota al usuario despues de corregir la matricula en caso de error\n flow.set(\"nota_avise_basculista_done\", false) // nota al usuario de aviso al basculista\n flow.set(\"nota_resumen_mostrada\", false) // indica que la nota de resumen luego de presentar identificacion ya se mostro (nodo QR / RFID)\n flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n flow.set(\"matricula\", \"Sin Matricula\")\n flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n flow.set(\"badplate\", false)\n flow.set(\"distance_flag_SET\", false)\n flow.set(\"semaforoabierto\", true) // flag para gestion del semaforo desde websocket\n //Atributos del vehiculo, leidos de la BD al momento de revisar si la matricula existe en BD\n flow.set(\"pma\", 0)\n flow.set(\"tara\", 0)\n flow.set(\"tipo_movimiento\", \"nodefinido\")\n flow.set(\"register\", {})\n flow.set(\"movimiento_enviado\", false)\n flow.set(\"matriculacheck_solicitada\", false) // flag utilizado para no repetir el envio de la revision de matricula en el nodo Matricula\n \n if (flow.get(\"switch_2_Totem_page\")) { //En caso que este flag haya sido habilitado en configuracion \n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta y cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n \n node.send([null, null, null, null, null, { payload: \"\" }, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n else {\n //eliminamos cualquier posible ventana de notificacion que haya quedado abierta\n node.send([null, null, null, null, null, { payload: \"\" }, null, null]);\n }\n }\n //==========================================================================================================================\n flow.set(\"peso_estable_flag\", false)\n flow.set(\"peso_estable_audio_flag\", true)\n flow.set(\"peso_estable\", 0)\n flow.set(\"fin_pesada_flag\", false)\n //flow.set(\"totem_master\", false) // flag para NO declarar peso estable si lo encontramos en false (ver nodo \"detector rx\") y para no enviar movimientos a Base de datos ni a servidor\n if (flow.get(\"totem_qty\") == 1) { flow.set(\"totem_master\", true) } // en el caso de un solo totem. Este dispositivo siempre sera el master\n flow.set(\"firma_activa\", false)\n flow.set(\"QR_ok_flag\", false);\n flow.set(\"RFID_ok_flag\", false);\n flow.set(\"last_QR\", \"-\")\n flow.set(\"last_RFID\", \"-\")\n flow.set(\"botonsalida\", false)\n flow.set(\"vehiculo_en_posicion\", false)\n flow.set(\"salida_valida_flag\", false)\n \n flow.set(\"aviso_pma_hecho\", false) // reset del flag indicador de PMA\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"matricula_editada_flag\", false)\n //flow.set(\"matricula\", \"Sin Matricula\")\n //flow.set(\"snapshot_rq_flag\", false)\n //flow.set(\"nombre_imagen\", \"sin-nombre-de-imagen\")\n //flow.set(\"badplate\", false)\n flow.set(\"firma_ok_flag\", false)\n flow.set(\"movimiento_registrado_flag\", false)\n if (flow.get((\"semaforoabierto\"))){ // si el semaforo ha sido manipulado desde websocket entonces no lo tocamos\n flow.set(\"semaforo\", \"green\")\n }\n flow.set(\"window_men_m1\", \"\"); // borra posibles mensajes en pantalla \n flow.set(\"window_men_m2\", \"\"); \n flow.set(\"window_men_m3\", \"\");\n flow.set(\"window_id_m4\", \"\");\n flow.set(\"window_id_m2\", \"\");\n \n \n}\nelse {// ************************ peso > pmin *****************************************\n if (flow.get(\"peso_bajo_flag\")) {\n flow.set(\"peso_min_time\", new Date().getTime()) // marca momento en que se detecta peso > peso min\n //node.warn(\"peso_min_time = \" + flow.get(\"peso_min_time\"))\n flow.set(\"horaentrada\", new Date(flow.get(\"peso_min_time\")).toLocaleString()) // Convierte a formato legible\n // evento de bascula ON para cuando hay un solo Totem en la bascula (sin sensor remoto)\n /*\n if (flow.get(\"peso_trigger_ON\") == false) {\n flow.set(\"peso_trigger_ON\", true) // \n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null])\n }\n */\n node.send([null, null, null, { payload: 1, topic: \"peso_ON\" }, null, null, null, null]) // sacamos evento de bascula ON cuando no hay sensor remoto\n //flow.set(\"matricula_leida_flag\", false)\n //flow.set(\"matricula_formato_flag\", false)\n flow.set(\"matricula_ok_flag\", false)\n flow.set(\"badplate\", false) // inicializamos flag en caso que haya sido enviado cuando peso < pmin \n flow.set(\"vehiculo_presente_flag\", true);\n flow.set(\"ID_enviado\", false) // activamos flag para envio de un unico RFID / QR con peso > pmin\n flow.set(\"esperando_id\", true)\n flow.set(\"peso_bajo_flag\", false);\n\n flow.set(\"semaforo\", \"red\")\n node.send([{ payload: 1 }, null, null, null, null, null, null, null]) // generamos un nuevo UUID\n setTimeout(function () {\n let new_register = {\n uuid: flow.get(\"new_uuid\"),\n horaentrada: flow.get(\"horaentrada\"),\n vial: flow.get(\"numero_vial\"),\n totem: flow.get(\"totem_id\"),\n sincro: false,\n modo: flow.get(\"modo_totem\"),\n firmaobligatoria: flow.get(\"firma_obligatoria\"),\n id_seleccionado: \"no recibido\",\n nombre_firma: \"No Habilitada\",\n QR: \"-\",\n RFID: \"-\",\n matricula: \"Sin Matricula\",\n nombre_imagen: \"Sin Matricula\",\n sentido: \"No conocido\"\n }\n flow.set(\"register\", new_register)\n }, 1000)\n\n if (flow.get(\"switch_2_Totem_page\")) { // si ha sido habilitado cambiamos a la ventana principal de Totem en caso de haber quedado otra ventana abierta\n node.send([null, null, null, null, null, null, { \"payload\": { \"tab\": \"Totem\" } }, null]);\n }\n \n if ((flow.get(\"modo_totem\") == \"C\" || flow.get(\"modo_totem\") == \"D\" ) && !flow.get(\"supervisor\")){\n if(flow.get(\"botonsalida_activo\")){\n flow.set(\"botonsalida\", true)\n }\n }\n }\n if (flow.get(\"peso_estable_flag\")) {\n flow.set(\"peso\", flow.get(\"peso_estable\"));\n } \n\n \n //-------------------------------procesamiento de la lista de materiales-----------------------------------------------------\n //if (flow.get(\"lista_flag\") && flow.get(\"supervisor\")) {\n if (flow.get(\"lista_flag\")) {\n flow.set(\"lista_flag\", false) // evita otra entrada a esta secuencia para esta misma lista\n var lista = flow.get(\"lista_array\") // lista con todos los materiales y niveles juntos\n const lista_size = flow.get(\"lista_array\").length\n let j = 0; let k = 0; let i = 0; let maxlevel = 0;\n for (i = 0; i < lista_size; i++) { // calculamos el nivel maximo que tiene esta lista de menu\n if (parseInt(lista[i].nivel) > maxlevel) {\n maxlevel = parseInt(lista[i].nivel)\n }\n }\n flow.set(\"maxlevel\", maxlevel + 1) // guardamos el maximo nivel de menu identificado en la lista\n flow.set(\"selections\", \"\") //inicializamos con ninguna seleccion\n if (flow.get(\"menu_inicio\")) {\n flow.set(\"startmenu_flag\", true)\n }\n\n }\n\n //----------------------------------- FIN Lista de Materiales -----------------------------------------------------------------------\n}\n\nreturn ([null, null, null, null, msg, null, null, null]);\n", "outputs": 7, "timeout": 0, "noerr": 0, @@ -4207,7 +4208,8 @@ "41b9eef871e59dd2" ], [ - "944c9f4b068e0946" + "944c9f4b068e0946", + "4ab4a211f9ce33d9" ], [ "83a963e6bc339f0e" @@ -4220,7 +4222,7 @@ "z": "953e8740401d175c", "g": "646bdfb9988a1708", "name": "Analisis del modo 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)\n\n if (flow.get(\"firma_obligatoria\") && !flow.get(\"firma_ok_flag\") && !flow.get(\"supervisor\") && (!flow.get(\"menu_activo\") || (flow.get(\"menu_activo\") && flow.get(\"menu_seleccionado_flag\")))) { //chequea si tenemos que solicitar firma\n /*El if anterior se cumple si:\n - firma_obligatoria es true y firma_ok_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 parece que con un solo parametro es suficiente\n flow.set(\"firma_flag\", true)\n setTimeout(() => {\n node.send([{ \"payload\": { \"tab\": \"Firma\" } }, { payload: \"firma\" }, null, null])\n }, 500);\n\n }\n\n //=============================================================================================================================================\n //====================================================== MODO DE OPERACION ====================================================================\n //=============================================================================================================================================\n let modo = flow.get(\"modo_totem\")\n // -----------------------------------------------------COMUN PARA TODOS LOS MODOS ------------------------------------------------------------\n //let QR_flag = flow.get(\"QR_ok_flag\") || false;\n //let RFID_flag = flow.get(\"RFID_ok_flag\") || false;\n let detector_flag = (flow.get(\"distance_flag_SET\") && (flow.get(\"sentido\") == \"entrada\") && flow.get(\"sensor_distancia_local\")) || false;\n let boton_flag = flow.get(\"salida_valida_flag\") || false;\n let matricula_flag = flow.get(\"matricula_ok_flag\") || false;\n let register_flag = flow.get(\"movimiento_registrado_flag\");\n let firma_flag = flow.get(\"firma_ok_flag\")\n let menu_activo = flow.get(\"menu_activo\") // el menu activo se configura en el archivo de configuracion\n let menu_selected = flow.get(\"menu_seleccionado_flag\") // este flag se activa cuando el conductor selecciona el residuo del menu y lo envia (en caso de menu_activo = true)\n let ID_verificado = flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")\n \n // Reglas de obligatoriedad configurables en archivo de configuracion\n //let QR_obligatorio = flow.get(\"QR_obligatorio\") || false;\n //let RFID_obligatorio = flow.get(\"RFID_obligatorio\") || false;\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 // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n //let QR_ok = !QR_obligatorio || QR_flag;\n //let RFID_ok = !RFID_obligatorio || RFID_flag;\n let ID_ok = !ID_obligatorio || ID_verificado\n let detector_ok = !detector_obligatorio || detector_flag;\n let boton_ok = !boton_obligatorio || boton_flag;\n let firma_ok = !firma_obligatoria || firma_flag;\n let matricula_ok = !matricula_obligatoria || matricula_flag\n let seleccion_ok\n if(flow.get(\"tipo_movimiento\") == \"inicial\"){\n seleccion_ok = !menu_activo || menu_selected || ID_verificado // Si el menu esta activo el ID_verificado permite saltar la seleccion del residuo\n }\n else if(flow.get(\"tipo_movimiento\") == \"final\"){\n //seleccion_ok = !menu_activo || menu_selected || ID_verificado || boton_flag\n seleccion_ok = true\n ID_ok = !flow.get(\"salida_ID_obligatorio\") || ID_verificado\n }\n /*\n if (flow.get(\"identificacion_esp\") && flow.get(\"identificacion_pendiente\")) {\n QR_ok = !QR_obligatorio && flow.get(\"QR_verificado\")\n RFID_ok = !RFID_obligatorio && flow.get(\"RFID_verificado\")\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 el vehiculo abandone la bascula es decir cuando peso < pmin\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO qye 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;\n \n node.warn(\"todos obligatorios = \" + todos_obligatorios_ok)\n node.warn(\"ID_ok = \" + ID_ok + \" ; detector_ok = \" + detector_ok + \" ; register_flag = \" + register_flag + \" ; seleccion = \" + seleccion_ok + \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok )\n \n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n //node.warn(\"matricula ok\")\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n /*\n if (flow.get(\"identificacion_esp_aplicada\")) {\n new_register.matricula = \"Sin Matricula\"\n new_register.nombre_imagen = \"Sin Matricula\"\n }\n */\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 = flow.get(\"nombre_firma\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")){\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n if (!flow.get(\"movimiento_enviado\")){\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n //node.warn(\"revisando QR / RFID flags\")\n //if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || flow.get(\"salida_valida_flag\") || flow.get(\"peso_estable_flag\")) {\n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")) {\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\"));\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 eslementos:\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 el vehiculo abandone la bascula es decir cuando peso < pmin\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO qye 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;\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 el vehiculo abandone la bascula es decir cuando peso < pmin por primera vez\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;\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_ok_flag\") || flow.get(\"RFID_ok_flag\")) {\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 vehiculo abandone la bascula es decir cuando peso < pmin\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;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n\n break;\n\n }// termina el codigo del SWITCH CASE\n //*************************************************** PREPARACION Y ENVIO DEL MOVIMIENTO *******************************************************\n if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")&& !flow.get(\"movimiento_enviado\")) {\n let date = new Date();\n let timestamp = parseInt(date.getTime() / 1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n\n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n\n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")) { // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n //let msg_plate = { payload: flow.get(\"matricula_image\"), filename: flow.get(\"path_images\") + flow.get(\"nombre_imagen\") } // guardamos archivo con imagen en disco local\n\n //flow.set(\"register2API\", new_register) // guardamos el objeto json completo con imagen de matricula e imagen de firma \n\n flow.set(\"movimiento_registrado_flag\", false) // evitamos que podamos entrar en este espacio hasta nuevo registro\n\n // *********************** preparamos json con movimiento para enviar al supervisor local de la bascula *****************\n let msg_mov = { payload: {} }\n new_register.tara = flow.get(\"tara\")\n new_register.destareautomatico = flow.get(\"destareautomatico\")\n msg_mov.payload.device = \"supervisor\"\n msg_mov.payload.totem_id = flow.get(\"totem_id\")\n msg_mov.payload.accion = \"movimiento\"\n //msg_mov.payload.tipo = flow.get(\"modelo\") // entrada / salida\n msg_mov.payload.tipomovimiento = flow.get(\"tipo_movimiento\")\n //msg_mov.payload.urlapi = flow.get(\"url_API\")\n msg_mov.payload.movimiento = new_register // enviamos el registro del movimiento con las imagenes de matricula y de firma\n flow.set(\"movimiento_enviado\", true)\n flow.set(\"new_register\", {}) // inicializamos el registro para evitar cualquier posible duplicado en bd\n node.send([null, null, msg_mov, null])\n }\n\n }\n}\nreturn ([null, null, null, msg])", + "func": "//***************************** Selecciona Modo de Operacion **************************************************\nif (!flow.get(\"supervisor\")) {\n if (flow.get(\"peso_estable_flag\")) { //El peso estable se obtiene cuando el vehiculo esta frente al Totem (QR / RFID o sino Detector Local ON)\n\n if (flow.get(\"firma_obligatoria\") && !flow.get(\"firma_ok_flag\") && !flow.get(\"supervisor\") && (!flow.get(\"menu_activo\") || (flow.get(\"menu_activo\") && flow.get(\"menu_seleccionado_flag\")))) { //chequea si tenemos que solicitar firma\n /*El if anterior se cumple si:\n - firma_obligatoria es true y firma_ok_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 parece que con un solo parametro es suficiente\n flow.set(\"firma_flag\", true)\n setTimeout(() => {\n node.send([{ \"payload\": { \"tab\": \"Firma\" } }, { payload: \"firma\" }, null, null])\n }, 500);\n\n }\n\n //=============================================================================================================================================\n //====================================================== MODO DE OPERACION ====================================================================\n //=============================================================================================================================================\n let modo = flow.get(\"modo_totem\")\n // -----------------------------------------------------COMUN PARA TODOS LOS MODOS ------------------------------------------------------------\n //let QR_flag = flow.get(\"QR_ok_flag\") || false;\n //let RFID_flag = flow.get(\"RFID_ok_flag\") || false;\n let detector_flag = (flow.get(\"distance_flag_SET\") && (flow.get(\"sentido\") == \"entrada\") && flow.get(\"sensor_distancia_local\")) || false;\n let boton_flag = flow.get(\"salida_valida_flag\") || false;\n let matricula_flag = flow.get(\"matricula_ok_flag\") || false;\n let register_flag = flow.get(\"movimiento_registrado_flag\");\n let firma_flag = flow.get(\"firma_ok_flag\")\n let menu_activo = flow.get(\"menu_activo\") // el menu activo se configura en el archivo de configuracion\n let menu_selected = flow.get(\"menu_seleccionado_flag\") // este flag se activa cuando el conductor selecciona el residuo del menu y lo envia (en caso de menu_activo = true)\n let ID_verificado = flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")\n \n // Reglas de obligatoriedad configurables en archivo de configuracion\n //let QR_obligatorio = flow.get(\"QR_obligatorio\") || false;\n //let RFID_obligatorio = flow.get(\"RFID_obligatorio\") || false;\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 // Evaluación de cumplimiento de Flags actuales y Flags obligatorios\n //let QR_ok = !QR_obligatorio || QR_flag;\n //let RFID_ok = !RFID_obligatorio || RFID_flag;\n let ID_ok = !ID_obligatorio || ID_verificado\n let detector_ok = !detector_obligatorio || detector_flag;\n let boton_ok = !boton_obligatorio || boton_flag;\n let firma_ok = !firma_obligatoria || firma_flag;\n let matricula_ok = !matricula_obligatoria || matricula_flag\n let seleccion_ok\n if(flow.get(\"tipo_movimiento\") == \"inicial\"){\n seleccion_ok = !menu_activo || menu_selected || ID_verificado // Si el menu esta activo el ID_verificado permite saltar la seleccion del residuo\n }\n else if(flow.get(\"tipo_movimiento\") == \"final\"){\n //seleccion_ok = !menu_activo || menu_selected || ID_verificado || boton_flag\n seleccion_ok = true\n ID_ok = !flow.get(\"salida_ID_obligatorio\") || ID_verificado\n }\n /*\n if (flow.get(\"identificacion_esp\") && flow.get(\"identificacion_pendiente\")) {\n QR_ok = !QR_obligatorio && flow.get(\"QR_verificado\")\n RFID_ok = !RFID_obligatorio && flow.get(\"RFID_verificado\")\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 el vehiculo abandone la bascula es decir cuando peso < pmin\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO qye 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;\n \n node.warn(\"todos obligatorios = \" + todos_obligatorios_ok)\n node.warn(\"ID_ok = \" + ID_ok + \" ; detector_ok = \" + detector_ok + \" ; register_flag = \" + register_flag + \" ; seleccion = \" + seleccion_ok + \" ; matricula = \" + matricula_ok + \" ; boton = \" + boton_ok )\n \n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n //Agregamos al registro los nuevos datos recogidos\n //node.warn(\"matricula ok\")\n let new_register = flow.get(\"register\")\n new_register.matricula = flow.get(\"matricula\")\n new_register.matriculaeditada = flow.get(\"matricula_editada_flag\")\n new_register.nombre_imagen = flow.get(\"nombre_imagen\")\n /*\n if (flow.get(\"identificacion_esp_aplicada\")) {\n new_register.matricula = \"Sin Matricula\"\n new_register.nombre_imagen = \"Sin Matricula\"\n }\n */\n if (flow.get(\"tipo_movimiento\") == \"inicial\"){\n new_register.qr = flow.get(\"last_QR\")\n }\n else if (flow.get(\"tipo_movimiento\") == \"final\"){\n new_register.qrsalida = flow.get(\"last_QR\")\n }\n \n new_register.rfid = flow.get(\"last_RFID\")\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = flow.get(\"nombre_firma\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")){\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n if (!flow.get(\"movimiento_enviado\")){\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n }\n //------------------------------------------------------------------------------------------------------------------------------------------\n //node.warn(\"revisando QR / RFID flags\")\n //if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\") || flow.get(\"salida_valida_flag\") || flow.get(\"peso_estable_flag\")) {\n if (flow.get(\"QR_verificado\") || flow.get(\"RFID_verificado\")) {\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\"));\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 eslementos:\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 el vehiculo abandone la bascula es decir cuando peso < pmin\n // Adidionalmente se revisa si existe algun parametro OBLIGATORIO qye 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;\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 el vehiculo abandone la bascula es decir cuando peso < pmin por primera vez\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;\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_ok_flag\") || flow.get(\"RFID_ok_flag\")) {\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 vehiculo abandone la bascula es decir cuando peso < pmin\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;\n if (todos_obligatorios_ok) { // Cerramos el registro con los parametros hasta ahora recogidos\n\n //Agregamos al registro los nuevos datos recogidos\n let new_register = flow.get(\"register\")\n new_register.matricula = \"Sin Camara\"\n new_register.matriculaeditada = false\n new_register.nombre_imagen = \"Sin Camara\"\n new_register.qr = \"Sin Lector de QR\"\n new_register.rfid = \"Sin Lector de RFID\"\n new_register.sentido = flow.get(\"sentido\")\n new_register.botonvalidacion = flow.get(\"salida_valida_flag\")\n if (flow.get(\"firma_obligatoria\") && flow.get(\"firma_ok_flag\")) {\n new_register.nombre_firma = \"firma-\" + flow.get(\"nombre_imagen\")\n new_register.firmaobligatoria = true\n }\n else {\n new_register.nombre_firma = \"No Habilitada\"\n new_register.firmaobligatoria = false\n }\n if (flow.get(\"menu_activo\")) {\n new_register.id_seleccionado = flow.get(\"id_seleccionado\")\n }\n flow.set(\"register\", new_register)\n flow.set(\"movimiento_registrado_flag\", true)\n flow.set(\"fin_pesada_flag\", true)\n }\n\n break;\n\n }// termina el codigo del SWITCH CASE\n //*************************************************** PREPARACION Y ENVIO DEL MOVIMIENTO *******************************************************\n if (flow.get(\"movimiento_registrado_flag\") && !flow.get(\"supervisor\") && flow.get(\"totem_master\") && (flow.get(\"tipo_movimiento\") != \"nodefinido\")&& !flow.get(\"movimiento_enviado\")) {\n let date = new Date();\n let timestamp = parseInt(date.getTime() / 1000);\n flow.set(\"horasalida\", new Date(date.getTime()).toLocaleString()) // Convierte a formato legible\n\n let new_register = flow.get(\"register\")\n new_register.horasalida = flow.get(\"horasalida\")\n new_register.pesoestable = flow.get(\"peso_estable\")\n new_register.timestamp = timestamp\n //hay que revisar imagen, QR y RFID ya que no en todos los casos estan presentes\n\n let obj = new_register;\n delete obj.sincro\n new_register = obj\n new_register.imagen = flow.get(\"matricula_image\")\n if (flow.get(\"firma_obligatoria\")) { // cambiamos \"firma_habilitada\" por \"firma_obligatoria\"\n new_register.firma = flow.get(\"last_firma\")\n }\n\n //let msg_plate = { payload: flow.get(\"matricula_image\"), filename: flow.get(\"path_images\") + flow.get(\"nombre_imagen\") } // guardamos archivo con imagen en disco local\n\n //flow.set(\"register2API\", new_register) // guardamos el objeto json completo con imagen de matricula e imagen de firma \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])", "outputs": 4, "timeout": 0, "noerr": 0, @@ -4396,7 +4398,7 @@ "className": "", "topic": "", "name": "edit plate", - "x": 1280, + "x": 1320, "y": 1220, "wires": [ [ @@ -4456,12 +4458,10 @@ "5420d37f8224c191" ], [ - "db3e9975c8f562b6", - "fc6c8adcf31b5734" + "db3e9975c8f562b6" ], [ - "f5343bf87806ece4", - "4ab4a211f9ce33d9" + "f5343bf87806ece4" ] ] }, @@ -5365,7 +5365,7 @@ "showMsgUib": false, "title": "", "descr": "", - "editurl": "vscode://vscode-remote/ssh-remote+192.168.11.24/home/trypton/.node-red/projects/Bascula_Autonoma_1/uibuilder/totem/?windowId=_blank", + "editurl": "vscode://vscode-remote/ssh-remote+192.168.0.29/home/trypton/.node-red/projects/Bascula_Autonoma_1/uibuilder/totem/?windowId=_blank", "x": 3720, "y": 2200, "wires": [ @@ -5412,7 +5412,7 @@ "z": "953e8740401d175c", "g": "e3bc37824e09b774", "name": "buttons \\n decoder", - "func": "\nif (msg.topic === \"tipoconfig\"){\n let tiposDatosGlobal = flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []};\n\nconst tipo = msg.payload.tipo; // ej: 2\nconst datos = msg.payload.datos; // array con los parámetros\n\ntiposDatosGlobal[tipo] = datos;\n\nflow.set(\"tiposDatosGlobal\", tiposDatosGlobal);\n\nreturn ;\n}\nelse if (msg.payload.hasOwnProperty(\"seccion\")) {\n\n\n /* Los diferentes \"case\" corresponden a la pulsacion de botones de los diferentes menus de configuracion\n Cada menu solicitado mediante el click de un boton devuelve el nombre del \"div\" en el archivo html que debemos habilitar\n para que se muestre en pantalla.\n Si la entrada no consigue ningun case que se ajuste entonces caemos en el \"default\" y ahi buscamos primero si hay\n algun mensaje en \"origen\", lo que corresponde a la actualizacion de alguna de las tablas dinamicas que se generan\n para modificar cada tipo de parametro. Luego se revisan los \"modalCallback\" los cuales no indican que la respuesta\n de la notificacion de alguna accion importante ha sido positiva (\"SI\").\n \n */\n\n switch (msg.payload.seccion) {\n\n case \"menu-principal\": // boton de configuracion en pantalla principal para acceder al menu principal \n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"editar\": // boton para acceder al menu de edicion de la configuracion\n return { payload: { pantalla: \"editar\" } }\n\n case \"pruebas\": // boton para acceder al menu de pruebas del sistema\n return { payload: { pantalla: \"pruebas\" } }\n\n case \"semaforo\": // boton para acceder al menu prueba del semaforo\n return { payload: { pantalla: \"semaforo\" } }\n\n case \"otras\": // boton para acceder al menu de otras acciones\n return { payload: { pantalla: \"otras\" } }\n\n case \"regresar\": // boton para regresar al menu principal desde otras acciones y desde menu de pruebas del sistema\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"salvar\": // boton para almacenar los cambios en el archivo de configuracion en el menu de edicion de la configuracion\n return ([{ payload: { pantalla: \"editar\" }, modalText: \"Desea MODIFICAR el archivo de CONFIGURACION ?\", modalCallback: \"modificar\" }, null, null, null])\n\n case \"cancelar\": // boton para cancelar y salir del menu de editar configuracion\n return ([{ payload: { pantalla: \"menu-principal\" } }, null])\n\n case \"semaforo_on\": // boton para poner el semaforo en rojo\n flow.set(\"semaforo\", \"red\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"firebrick\" }, null, { payload: 0 }])\n\n case \"semaforo_off\": // boton para poner el semaforo en verde\n flow.set(\"semaforo\", \"green\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"green\" }, null, { payload: 1 }])\n\n case \"salir-semaforo\": // boton de salida de la pantalla de prueba del semaforo\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"barrera\": // boton de activar barrera\n return ({ payload: { pantalla: \"barrera\" }, barrera: false })\n\n case \"general\": // boton para ver / modificar tabla con los parametros generales\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"general\", tabla: flow.get(\"config_general\") }, null, null])\n\n case \"camara\": // boton para ver / modificar tabla con los parametros de la camara\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"camara\", tabla: flow.get(\"config_camara\") }, null, null])\n\n case \"conexion\": // boton para ver / modificar tabla con los parametros de conexion\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"conexion\", tabla: flow.get(\"config_conex\") }, null, null])\n\n case \"sensores\": // boton para ver / modificar tabla con los parametros de sensores\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"sensores\", tabla: flow.get(\"config_sensor\") }, null, null])\n\n case \"mensajes\": // boton para ver / modificar tabla con los parametros de los mensajes\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"mensajes\", tabla: flow.get(\"config_mensajes\") }, null, null])\n\n case \"tiempos\": // boton para ver / modificar tabla con los parametros del tiempo\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"tiempos\", tabla: flow.get(\"config_tiempos\") }, null, null])\n\n case \"aplicar\": // boton para aplicar la configuracion al RPi, en el menu-principal\n return ([{ payload: { pantalla: \"menu-principal\" }, topic: \"menu-principal\", modalText: \"Desea Recargar la CONFIGURACION ?\", modalCallback: \"recargar\" }, null, null])\n\n case \"reboot\": // boton para resetear el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea Reiniciar el TOTEM ?\", modalCallback: \"reiniciar\" }, null, null])\n\n case \"apagar\": // boton para apagar el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea APAGAR el TOTEM ?\", modalCallback: \"apagar\" }, null, null])\n\n case \"snapshot\": // boton para pedir snapshot\n flow.set(\"snapshot_cam\", true)\n flow.set(\"escuchar_cam\", false)\n let msgrqt = {}\n msgrqt.payload = {}\n msgrqt.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n msgrqt.topic = \"snapshot_rqtd\"\n return ([{ payload: { pantalla: \"snapshot\" }, topic: \"snapshot\" }, null, null, null, null, msgrqt])\n\n case \"escuchar\": // boton para escuchar camara ( recibir todas la imagenes que envie)\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", true)\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"left\": // Boton para ir a la imagen anterior en escuchar camara\n flow.set(\"getfromarray\", \"left\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"right\": // Boton para ir a la siguiente imagen en escuchar camara\n flow.set(\"getfromarray\", \"right\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"salir-snapshot\": // boton de salida de la pantalla de ver snapshot\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"salir-barrera\": // boton de salida de la barrera\n\n return ({ payload: { pantalla: \"pruebas\" }, barrera: false })\n\n case \"salir-escuchar\": // boton de salida de la pantalla de escuchar la camara\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n flow.set(\"snapshot_array\", [])\n flow.set(\"snapshot_readindex\", 0)\n flow.set(\"snapshot_saveindex\", 0)\n flow.set(\"snapshot_indexmax\", 0)\n flow.set(\"getfromarray\", \"\")\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"activar-barrera\": // boton de activar barrera\n node.send([{ payload: { pantalla: \"barrera\" }, barrera: true }, null, null, null, null, null, null, { payload: 0 }])\n setTimeout(function () {\n node.send([null, null, null, null, null, null, null, { payload: 1 }])\n }, flow.get(\"relay2_pulse\"));\n return\n\n case \"cancel-table\": // boton de CANCEL de las tablas de configuracion de parametros\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"salir\": // boton de salida del menu principal\n return ({ payload: { pantalla: \"principal\" } })\n\n case \"tipos\": // boton de salida al menu editar\n msg.payload = {pantalla: \"tipos\", tiposDatos: flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []}};\n return (msg)\n\n case \"volver_tipos\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"ayuda\" } })\n\n case \"salir-ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n default: // chequeamos si tenemos acciones a realizar para lo cual revisamos el \"origen\" (actualizar en memoria sin preguntar usuario) y/o el \"modalCallback\" con esto sabemos de que tabla es el mensaje enviado por el MODAL\n node.send([null, null, null, null, null, null, msg])\n if (msg.origen == \"actualizar\") {// salvar en memoria la configuracion que ha sido modificada (el Topic nos dice cual configuracion)\n let myconfig = msg.payload.table // table contiene el resultado de leer la tabla con todos los valores normalizados en uibuilder\n \n switch (msg.topic) { // guardamos cambios en el tipo de configuracion correspondiente\n case \"general\":\n flow.set(\"config_general\", myconfig)\n break;\n case \"conexion\":\n // ==================================== VALIDAMOS todas las IP de la configuracion ==================================================\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n \n if (validarIP(myconfig[1].valor)){\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del DISPOSITIVO NO es correcta ?\", modalType:\"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[2].valor)) {\n //node.warn(\"valor 2 = \" + myconfig[2].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del ROUTER NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[5].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del WEBSOCKET NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[13].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del TOTEM pareja NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n break;\n case \"camara\":\n flow.set(\"config_camara\", myconfig)\n break;\n case \"sensores\":\n flow.set(\"config_sensor\", myconfig)\n break;\n case \"tiempos\":\n flow.set(\"config_tiempos\", myconfig)\n break;\n case \"mensajes\":\n flow.set(\"config_mensajes\", myconfig)\n break;\n }\n return { payload: { pantalla: \"editar\" } }\n }\n\n \n msg.hello = \"hello 3\"\n node.send([null, null, null, null, null, null, msg])\n return null\n\n }\n} // final del SWITCH\nelse if (msg.modalCallback == \"modificar\") {\n /*\n let config_totem = []\n config_totem = flow.get(\"config_general\").concat(flow.get(\"config_camara\"), flow.get(\"config_conex\"), flow.get(\"config_sensor\"), flow.get(\"config_mensajes\"), flow.get(\"config_tiempos\"), flow.get(\"tiposDatosGlobal\"))\n flow.set(\"config_totem\", config_totem)\n let jsontest = toJson(flow.get(\"config_totem\"));\n */\n let config_totem = {\n general: flow.get(\"config_general\") || [],\n camara: flow.get(\"config_camara\") || [],\n conexion: flow.get(\"config_conex\") || [],\n sensores: flow.get(\"config_sensor\") || [],\n mensajes: flow.get(\"config_mensajes\") || [],\n tiempos: flow.get(\"config_tiempos\") || [],\n tipos: flow.get(\"tiposDatosGlobal\") || {}\n };\n\n flow.set(\"config_totem\", config_totem);\n\n msg.payload = JSON.stringify(config_totem, null, 2) + \"\\n\\r\";\n //msg.payload = JSON.stringify(jsontest, null, 2) + \"\\n\\r\"; // el factor 2 agrega 2 espacio al inicio de cada elemento\n //y agrega tambien una linea lo cual es interesante para la legibilidad del formato y para que los clientes SFTP puedan\n //leer bien el archivo, como es el caso de Mobaxterm.\n\n return ([{ payload: { pantalla: \"menu-principal\" } }, msg, null])\n}\nelse if (msg.modalCallback == \"recargar\") {\n return ([null, null, null, { payload: 1 }])\n}\n\nelse if (msg.modalCallback == \"reiniciar\") {\n return ([null, null, null, null, { payload: \"sudo shutdown -r now\" }])\n}\n\nelse if (msg.modalCallback == \"apagar\") {\n return ([null, null, null, null, { payload: \"sudo poweroff\" }])\n}\n\n//============================================== FUNCIONES ==============================================================\n//esta funcion convierte un array con elementos [parametro, valor] en un objeto Json respetando los tipos de parametro (numerico, booleano, texto)\nfunction toJson(data) {\n let newJson = {}\n /*\n data.forEach(item => {\n let param = item.parametro;\n let value = item.valor;\n */\n for (let i = 0; i < data.length; i++) {\n let param = data[i].parametro;\n let value = data[i].valor;\n\n // Parseo de tipos igual que antes\n if (typeof value === 'string') {\n if (value.toLowerCase() === \"true\") {\n newJson[param] = true;\n } else if (value.toLowerCase() === \"false\") {\n newJson[param] = false;\n } else if (!isNaN(value) && value.trim() !== \"\") {\n newJson[param] = Number(value);\n } else {\n newJson[param] = value;\n }\n } else {\n // Por si el value ya viene como booleano o número real\n newJson[param] = value;\n }\n }\n return (newJson)\n}\n\n//=======================================================================================================================================\n\nfunction validarIP(ip) {\n const regex = /^(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/;\n return regex.test(ip);\n}", + "func": "\nif (msg.topic === \"tipoconfig\"){\n let tiposDatosGlobal = flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []};\n\nconst tipo = msg.payload.tipo; // ej: 2\nconst datos = msg.payload.datos; // array con los parámetros\n\ntiposDatosGlobal[tipo] = datos;\n\nflow.set(\"tiposDatosGlobal\", tiposDatosGlobal);\n\nreturn ;\n}\nelse if (msg.payload.hasOwnProperty(\"seccion\")) {\n\n\n /* Los diferentes \"case\" corresponden a la pulsacion de botones de los diferentes menus de configuracion\n Cada menu solicitado mediante el click de un boton devuelve el nombre del \"div\" en el archivo html que debemos habilitar\n para que se muestre en pantalla.\n Si la entrada no consigue ningun case que se ajuste entonces caemos en el \"default\" y ahi buscamos primero si hay\n algun mensaje en \"origen\", lo que corresponde a la actualizacion de alguna de las tablas dinamicas que se generan\n para modificar cada tipo de parametro. Luego se revisan los \"modalCallback\" los cuales no indican que la respuesta\n de la notificacion de alguna accion importante ha sido positiva (\"SI\").\n \n */\n\n switch (msg.payload.seccion) {\n\n case \"menu-principal\": // boton de configuracion en pantalla principal para acceder al menu principal \n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"editar\": // boton para acceder al menu de edicion de la configuracion\n return { payload: { pantalla: \"editar\" } }\n\n case \"pruebas\": // boton para acceder al menu de pruebas del sistema\n return { payload: { pantalla: \"pruebas\" } }\n\n case \"semaforo\": // boton para acceder al menu prueba del semaforo\n return { payload: { pantalla: \"semaforo\" } }\n\n case \"otras\": // boton para acceder al menu de otras acciones\n return { payload: { pantalla: \"otras\" } }\n\n case \"regresar\": // boton para regresar al menu principal desde otras acciones y desde menu de pruebas del sistema\n return { payload: { pantalla: \"menu-principal\" } }\n\n case \"salvar\": // boton para almacenar los cambios en el archivo de configuracion en el menu de edicion de la configuracion\n return ([{ payload: { pantalla: \"editar\" }, modalText: \"Desea MODIFICAR el archivo de CONFIGURACION ?\", modalCallback: \"modificar\" }, null, null, null])\n\n case \"cancelar\": // boton para cancelar y salir del menu de editar configuracion\n return ([{ payload: { pantalla: \"menu-principal\" } }, null])\n\n case \"semaforo_on\": // boton para poner el semaforo en rojo\n flow.set(\"semaforo\", \"red\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"firebrick\" }, null, { payload: 0 }])\n\n case \"semaforo_off\": // boton para poner el semaforo en verde\n flow.set(\"semaforo\", \"green\")\n return ([{ payload: { pantalla: \"semaforo\" }, semaforo: \"green\" }, null, { payload: 1 }])\n\n case \"salir-semaforo\": // boton de salida de la pantalla de prueba del semaforo\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"barrera\": // boton de activar barrera\n return ({ payload: { pantalla: \"barrera\" }, barrera: false })\n\n case \"general\": // boton para ver / modificar tabla con los parametros generales\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"general\", tabla: flow.get(\"config_general\") }, null, null])\n\n case \"camara\": // boton para ver / modificar tabla con los parametros de la camara\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"camara\", tabla: flow.get(\"config_camara\") }, null, null])\n\n case \"conexion\": // boton para ver / modificar tabla con los parametros de conexion\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"conexion\", tabla: flow.get(\"config_conex\") }, null, null])\n\n case \"sensores\": // boton para ver / modificar tabla con los parametros de sensores\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"sensores\", tabla: flow.get(\"config_sensor\") }, null, null])\n\n case \"mensajes\": // boton para ver / modificar tabla con los parametros de los mensajes\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"mensajes\", tabla: flow.get(\"config_mensajes\") }, null, null])\n\n case \"tiempos\": // boton para ver / modificar tabla con los parametros del tiempo\n return ([{ payload: { pantalla: \"tabla-general\" }, topic: \"tiempos\", tabla: flow.get(\"config_tiempos\") }, null, null])\n\n case \"aplicar\": // boton para aplicar la configuracion al RPi, en el menu-principal\n return ([{ payload: { pantalla: \"menu-principal\" }, topic: \"menu-principal\", modalText: \"Desea Recargar la CONFIGURACION ?\", modalCallback: \"recargar\" }, null, null])\n\n case \"reboot\": // boton para resetear el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea Reiniciar el TOTEM ?\", modalCallback: \"reiniciar\" }, null, null])\n\n case \"apagar\": // boton para apagar el RPi en el menu de otras acciones\n return ([{ payload: { pantalla: \"otras\" }, topic: \"otras\", modalText: \"Desea APAGAR el TOTEM ?\", modalCallback: \"apagar\" }, null, null])\n\n case \"snapshot\": // boton para pedir snapshot\n flow.set(\"snapshot_cam\", true)\n flow.set(\"escuchar_cam\", false)\n let msgrqt = {}\n msgrqt.payload = {}\n msgrqt.url = \"http://\" + flow.get(\"camara_IP\") + \"/cgi-bin/trafficSnap.cgi?action=manSnap&channel=1\"\n msgrqt.topic = \"snapshot_rqtd\"\n return ([{ payload: { pantalla: \"snapshot\" }, topic: \"snapshot\" }, null, null, null, null, msgrqt])\n\n case \"escuchar\": // boton para escuchar camara ( recibir todas la imagenes que envie)\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", true)\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"left\": // Boton para ir a la imagen anterior en escuchar camara\n flow.set(\"getfromarray\", \"left\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"right\": // Boton para ir a la siguiente imagen en escuchar camara\n flow.set(\"getfromarray\", \"right\")\n return ([{ payload: { pantalla: \"escuchar\" }, topic: \"escuchar\" }, null, null])\n\n case \"salir-snapshot\": // boton de salida de la pantalla de ver snapshot\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"salir-barrera\": // boton de salida de la barrera\n\n return ({ payload: { pantalla: \"pruebas\" }, barrera: false })\n\n case \"salir-escuchar\": // boton de salida de la pantalla de escuchar la camara\n flow.set(\"snapshot_cam\", false)\n flow.set(\"escuchar_cam\", false)\n flow.set(\"snapshot_array\", [])\n flow.set(\"snapshot_readindex\", 0)\n flow.set(\"snapshot_saveindex\", 0)\n flow.set(\"snapshot_indexmax\", 0)\n flow.set(\"getfromarray\", \"\")\n return ({ payload: { pantalla: \"pruebas\" } })\n\n case \"activar-barrera\": // boton de activar barrera\n node.send([{ payload: { pantalla: \"barrera\" }, barrera: true }, null, null, null, null, null, null, { payload: 0 }])\n setTimeout(function () {\n node.send([null, null, null, null, null, null, null, { payload: 1 }])\n }, flow.get(\"relay2_pulse\"));\n return\n\n case \"cancel-table\": // boton de CANCEL de las tablas de configuracion de parametros\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"salir\": // boton de salida del menu principal\n return ({ payload: { pantalla: \"principal\" } })\n\n case \"tipos\": // boton de salida al menu editar\n msg.payload = {pantalla: \"tipos\", tiposDatos: flow.get(\"tiposDatosGlobal\") || {\"1\": [], \"2\": [], \"3\": [], \"4\": [], \"5\": [], \"6\": []}};\n return (msg)\n\n case \"volver_tipos\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n case \"ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"ayuda\" } })\n\n case \"salir-ayuda\": // boton de salida al menu editar\n return ({ payload: { pantalla: \"editar\" } })\n\n default: // chequeamos si tenemos acciones a realizar para lo cual revisamos el \"origen\" (actualizar en memoria sin preguntar usuario) y/o el \"modalCallback\" con esto sabemos de que tabla es el mensaje enviado por el MODAL\n node.send([null, null, null, null, null, null, msg])\n if (msg.origen == \"actualizar\") {// salvar en memoria la configuracion que ha sido modificada (el Topic nos dice cual configuracion)\n let myconfig = msg.payload.table // table contiene el resultado de leer la tabla con todos los valores normalizados en uibuilder\n \n switch (msg.topic) { // guardamos cambios en el tipo de configuracion correspondiente\n case \"general\":\n flow.set(\"config_general\", myconfig)\n break;\n case \"conexion\":\n // ==================================== VALIDAMOS todas las IP de la configuracion ==================================================\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n \n if (validarIP(myconfig[1].valor)){\n //node.warn(\"valor 1 = \" + myconfig[1].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del DISPOSITIVO NO es correcta ?\", modalType:\"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[2].valor)) {\n //node.warn(\"valor 2 = \" + myconfig[2].valor)\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del ROUTER NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[5].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del WEBSOCKET NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n if (validarIP(myconfig[12].valor)) {\n flow.set(\"config_conex\", myconfig)\n }\n else {\n return ([{ payload: { pantalla: \"editar\" }, topic: \"error\", modalText: \"La IP del TOTEM pareja NO es correcta ?\", modalType: \"notificacion\" }, null, null])\n }\n \n break;\n case \"camara\":\n flow.set(\"config_camara\", myconfig)\n break;\n case \"sensores\":\n flow.set(\"config_sensor\", myconfig)\n break;\n case \"tiempos\":\n flow.set(\"config_tiempos\", myconfig)\n break;\n case \"mensajes\":\n flow.set(\"config_mensajes\", myconfig)\n break;\n }\n return { payload: { pantalla: \"editar\" } }\n }\n\n \n msg.hello = \"hello 3\"\n node.send([null, null, null, null, null, null, msg])\n return null\n\n }\n} // final del SWITCH\nelse if (msg.modalCallback == \"modificar\") {\n /*\n let config_totem = []\n config_totem = flow.get(\"config_general\").concat(flow.get(\"config_camara\"), flow.get(\"config_conex\"), flow.get(\"config_sensor\"), flow.get(\"config_mensajes\"), flow.get(\"config_tiempos\"), flow.get(\"tiposDatosGlobal\"))\n flow.set(\"config_totem\", config_totem)\n let jsontest = toJson(flow.get(\"config_totem\"));\n */\n let config_totem = {\n general: flow.get(\"config_general\") || [],\n camara: flow.get(\"config_camara\") || [],\n conexion: flow.get(\"config_conex\") || [],\n sensores: flow.get(\"config_sensor\") || [],\n mensajes: flow.get(\"config_mensajes\") || [],\n tiempos: flow.get(\"config_tiempos\") || [],\n tipos: flow.get(\"tiposDatosGlobal\") || {}\n };\n\n flow.set(\"config_totem\", config_totem);\n\n msg.payload = JSON.stringify(config_totem, null, 2) + \"\\n\\r\";\n //msg.payload = JSON.stringify(jsontest, null, 2) + \"\\n\\r\"; // el factor 2 agrega 2 espacio al inicio de cada elemento\n //y agrega tambien una linea lo cual es interesante para la legibilidad del formato y para que los clientes SFTP puedan\n //leer bien el archivo, como es el caso de Mobaxterm.\n\n return ([{ payload: { pantalla: \"menu-principal\" } }, msg, null])\n}\nelse if (msg.modalCallback == \"recargar\") {\n return ([null, null, null, { payload: 1 }])\n}\n\nelse if (msg.modalCallback == \"reiniciar\") {\n return ([null, null, null, null, { payload: \"sudo shutdown -r now\" }])\n}\n\nelse if (msg.modalCallback == \"apagar\") {\n return ([null, null, null, null, { payload: \"sudo poweroff\" }])\n}\n\n//============================================== FUNCIONES ==============================================================\n//esta funcion convierte un array con elementos [parametro, valor] en un objeto Json respetando los tipos de parametro (numerico, booleano, texto)\nfunction toJson(data) {\n let newJson = {}\n /*\n data.forEach(item => {\n let param = item.parametro;\n let value = item.valor;\n */\n for (let i = 0; i < data.length; i++) {\n let param = data[i].parametro;\n let value = data[i].valor;\n\n // Parseo de tipos igual que antes\n if (typeof value === 'string') {\n if (value.toLowerCase() === \"true\") {\n newJson[param] = true;\n } else if (value.toLowerCase() === \"false\") {\n newJson[param] = false;\n } else if (!isNaN(value) && value.trim() !== \"\") {\n newJson[param] = Number(value);\n } else {\n newJson[param] = value;\n }\n } else {\n // Por si el value ya viene como booleano o número real\n newJson[param] = value;\n }\n }\n return (newJson)\n}\n\n//=======================================================================================================================================\n\nfunction validarIP(ip) {\n const regex = /^(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/;\n return regex.test(ip);\n}", "outputs": 8, "timeout": 0, "noerr": 0, @@ -6191,8 +6191,8 @@ "id": "53335688d117ec96", "type": "comment", "z": "953e8740401d175c", - "name": "Version 1.0 de bascula autonoma", - "info": "El 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\nversion 1.0. Este codigo de Bascula Autonoma sale a partir del Totem Autonomo. Todo el codigo relativo a la gestion de BAse de Datos se traslada al RPI Supervisor\nEn este RPi solo queda lo relativo a la gestion de sensores, camaras, lectores de Identioficacion, semaforo, barrera y la pantalla para que el usuario \npueda interactuar con el sistema como por ejemplo hacer seleccion del residuo a traves de un menu de seleccion.\n\nEn esta version se ha introducido el termino PMA(Peso Maximo Autorizado. Este es un valor que el Totem recibe cuando el Supervisor le envia la autorizacion\nde la matricula junto con la tara- El Totem revisa el peso estable del vehiculo con el PMA recibidoy en caso de ser superior se envia un aviso en la pantalla\nindicandole al conductor que debe retroceder ya que supera el peso admitido.\n\nOtra función que contiene esta version es el chequeo de la Tara. Si el valor recibido de la Tara es superior a cero entonces el movimiento inicial recinbido por el supervisor \nes enviado como movimiento cerrado al Servidor.Realmente para el Totem es transparente. La gestion de la Tara en efecto la hace el Supervisor una vez que recibe\nel movimiento inicial que envia el Totem.", + "name": "Version 1.1 de bascula autonoma", + "info": "**Version 1.1** Se han agregado nos nuevos campos a la tabla movimierntos_cerrados en el supervisor estos campos son \"qr_salida\" y \"rfid_salida\". La presencia de estos \ndos campos es para disponer de la identificaciob utilizada en salida en caso de hacerlo. Para ello en el nodo \"Analisis del modo de Operacion\" se evalua \nsi estamos en el movimiento inicial o final para ver cual campo es el que tenemos que rellenar. Est se hace el la linea nº 100\nSe ha moviso la inicializacion flow.set(\"distance_flag_SET\", false) al momento donde la bascula pasa de peso < pmin por primera vez. \nAntes se inicializaba cada vez que el peso que llegaba era menor que pmin. Esto podia ocasionar un error ya que el nodo detector perdia el control\nde este flag al ser inicializado cada vez que el peso < pmin.\n\nEl nodo \"matricula 2\" sustituye al nodo matricula anterior. Este nuevo contiene todas las modificaciones necesarias para adaptarse a los \nnuevos requerimientos de la bascula automatica\n\nPara que el QR pueda entrar en la planta es necesario que la matricula este disponible.\nEn caso de que la matricula leida sea diferente a la matricula obtenida en la BD luego de enviar el QR se toma la matricula leida de la BD\n\n**version 1.0.** Este codigo de Bascula Autonoma sale a partir del Totem Autonomo. Todo el codigo relativo a la gestion de BAse de Datos se traslada al RPI Supervisor\nEn este RPi solo queda lo relativo a la gestion de sensores, camaras, lectores de Identioficacion, semaforo, barrera y la pantalla para que el usuario \npueda interactuar con el sistema como por ejemplo hacer seleccion del residuo a traves de un menu de seleccion.\n\nEn esta version se ha introducido el termino PMA(Peso Maximo Autorizado. Este es un valor que el Totem recibe cuando el Supervisor le envia la autorizacion\nde la matricula junto con la tara- El Totem revisa el peso estable del vehiculo con el PMA recibidoy en caso de ser superior se envia un aviso en la pantalla\nindicandole al conductor que debe retroceder ya que supera el peso admitido.\n\nOtra función que contiene esta version es el chequeo de la Tara. Si el valor recibido de la Tara es superior a cero entonces el movimiento inicial recinbido por el supervisor \nes enviado como movimiento cerrado al Servidor.Realmente para el Totem es transparente. La gestion de la Tara en efecto la hace el Supervisor una vez que recibe\nel movimiento inicial que envia el Totem.", "x": 1290, "y": 800, "wires": [] @@ -6634,7 +6634,8 @@ "185e340354acf892" ], [ - "944c9f4b068e0946" + "944c9f4b068e0946", + "fc6c8adcf31b5734" ], [ "5a4bb45aef7a1433", @@ -6757,5 +6758,15 @@ "x": 1205, "y": 1180, "wires": [] + }, + { + "id": "2d5dd90ce0b556cf", + "type": "comment", + "z": "953e8740401d175c", + "name": "CAMBIO DEL ROOTFOLDER EN UIBUILDER", + "info": "Para cambiar la dirección de la carpeta donde se situan los archivos de UIBUILDER\nlo podemos hacer en el archivo de settings.js de nodered, modificando el parametro \"uibRoot\" el cual tiene \nalgo asi: uibRoot: '/home/trypton/.node-red/projects/bascula_autonoma3/uibuilder/'. Si cambiamos \nde proyecto solo tenemos que cambiar el nombre de la carpeta del proyecto. En el caso mostrado\nla carpeta del proyecto es bascula_autonoma3. luego de guardar el archivo setting.js es necesario\nre-arrancar el node red (node-red-restart)", + "x": 3870, + "y": 1960, + "wires": [] } ] \ No newline at end of file