[{"id":"146cda660ffa2aa4","type":"tab","label":"Càrrega dades contaminació","disabled":false,"info":"","env":[]},{"id":"96218aeda9d2849f","type":"inject","z":"146cda660ffa2aa4","name":"Inject config & start","props":[{"p":"ensList","v":"","vt":"json"},{"p":"sentiloEndPoint","v":"http://pre-api-sentilo.diba.cat","vt":"str"},{"p":"sufixComponent","v":"_AIR_QUALITY","vt":"str"},{"p":"tipusComponent","v":"air_quality","vt":"str"},{"p":"tipologies","v":"{\"1\":{\"magnitud\":\"1\",\"contaminant\":\"SO2\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_so2\"},\"6\":{\"magnitud\":\"6\",\"contaminant\":\"CO\",\"unitats\":\"mg/m3\",\"typology\":\"air_quality_co\"},\"7\":{\"magnitud\":\"7\",\"contaminant\":\"NO\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_no\"},\"8\":{\"magnitud\":\"8\",\"contaminant\":\"NO2\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_no2\"},\"9\":{\"magnitud\":\"9\",\"contaminant\":\"PM2.5\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_pm25\"},\"10\":{\"magnitud\":\"10\",\"contaminant\":\"PM10\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_pm10\"},\"12\":{\"magnitud\":\"12\",\"contaminant\":\"NOX\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_nox\"},\"14\":{\"magnitud\":\"14\",\"contaminant\":\"O3\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_o3\"},\"30\":{\"magnitud\":\"30\",\"contaminant\":\"C6H6\",\"unitats\":\"µg/m3\",\"typology\":\"air_quality_c6h6\"},\"65\":{\"magnitud\":\"65\",\"contaminant\":\"H2S\",\"unitats\":\"µg/m3\",\"typology\":\"air_pollutant\"}}","vt":"json"}],"repeat":"","crontab":"00 06 * * *","once":false,"onceDelay":0.1,"topic":"","x":160,"y":120,"wires":[["13c3043a1121e935"]]},{"id":"13c3043a1121e935","type":"array-loop","z":"146cda660ffa2aa4","name":"Itera ens","key":"al2614a4a09ddea153","keyType":"msg","reset":true,"resetValue":"value-null","array":"ensList","arrayType":"msg","x":420,"y":120,"wires":[[],["ee3b2fa02223dc64","3f6098fc11146c8f","6b7e658098514a7a"]]},{"id":"ee3b2fa02223dc64","type":"debug","z":"146cda660ffa2aa4","name":"Current ens","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":120,"wires":[]},{"id":"3f6098fc11146c8f","type":"delay","z":"146cda660ffa2aa4","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":420,"y":60,"wires":[["13c3043a1121e935"]]},{"id":"4ea217a6d4ce842b","type":"function","z":"146cda660ffa2aa4","name":"Prepara api req","func":"const ensInfo = msg.ensInfo;\nconst prefixComponent = ensInfo.prefixComponent;\nconst sensorPrefix = prefixComponent.toUpperCase() + '_';\n\n// Obtenim el timestamp de la dada més recent de les observacions\nconst sensors = msg.payload.sensors;\nlet lastTime = null;\nif (sensors) {\n for(var sensor of sensors) {\n if (sensor.sensor.startsWith('Sat')) {\n for(var observation of sensor.observations) {\n if (!lastTime) {\n lastTime = observation.time;\n }\n if (observation.time > lastTime) {\n lastTime = observation.time;\n }\n }\n }\n }\n}\n\n// La data inici serà avui, si tenim dades actuals\n// O avui - 30 dies, si no en tenim dades històriques\nconst today = new Date();\nvar d = new Date();\nd.setDate(d.getDate()-30);\nif (lastTime) {\n d = new Date(lastTime);\n d.setDate(d.getDate()+1);\n} \n\n// Qualitat de l’aire als punts de mesurament automàtics de la Xarxa de Vigilància i Previsió de la Contaminació Atmosfèrica\n// Docu serve¡i: https://analisi.transparenciacatalunya.cat/Medi-Ambient/Qualitat-de-l-aire-als-punts-de-mesurament-autom-t/tasf-thgu\n// Docu API: https://dev.socrata.com/foundry/analisi.transparenciacatalunya.cat/tasf-thgu\n\n// Filtre per nom estció\nconst nomEstacio = ensInfo.nomEstacio;\nconst filtreNomEstacio = 'nom_estacio='+nomEstacio;\n\n// Filtrat per dates (si no demanem per hores, agafa el dia sencer)\n// Format data: 1995-01-22 ó 2014-10-13T00:00:00.000\nconst dataInici = d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0'+d.getDate()).slice(-2);\nconst dataFi = today.getFullYear() + '-' + ('0'+(today.getMonth()+1)).slice(-2) + '-' + ('0'+today.getDate()).slice(-2);\nconst filtreWhere = '$where=data between \\''+dataInici+'\\' and \\''+dataFi+'\\'';\n\n// Construïm la url\nconst url = 'https://analisi.transparenciacatalunya.cat/resource/tasf-thgu.json?'+filtreNomEstacio+'&'+filtreWhere;\nmsg.url = url;\nmsg.method = 'GET';\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":140,"y":320,"wires":[["450556fecae4d436","b69fb01509658487"]]},{"id":"450556fecae4d436","type":"debug","z":"146cda660ffa2aa4","name":"API data url","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"url","targetType":"msg","statusVal":"","statusType":"auto","x":130,"y":360,"wires":[]},{"id":"d4760a1172441dfd","type":"debug","z":"146cda660ffa2aa4","name":"Last ens sensors obs","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":660,"y":260,"wires":[]},{"id":"b69fb01509658487","type":"http request","z":"146cda660ffa2aa4","name":"[GET] api data","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":380,"y":320,"wires":[["1a71ac65996c2477","73bbd720b9e1f925"]]},{"id":"1a71ac65996c2477","type":"debug","z":"146cda660ffa2aa4","name":"API data response","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":360,"wires":[]},{"id":"73bbd720b9e1f925","type":"function","z":"146cda660ffa2aa4","name":"Tractament dades estacio","func":"const DateTime = luxon.DateTime;\n\nconst ensInfo = msg.ensInfo;\n//const component = ensInfo.prefixComponent + '_POLLUTION';\nconst sufixComponent = msg.sufixComponent;\nconst prefixComponent = ensInfo.prefixComponent\nconst component = prefixComponent + sufixComponent;\nconst tipusComponent = msg.tipusComponent;\nconst prefixSensor = ensInfo.prefixComponent;\nconst tipologies = msg.tipologies;\nconst dadesEstacio = msg.payload;\n\nlet sensorsToCreate = [];\nlet observations = {};\nfor(var dadaEstacio of dadesEstacio) {\n // Càlcul de la tipologia\n let type = tipologies[dadaEstacio.magnitud].typology;\n if (!type)\n type = 'status';\n \n const sensor = prefixSensor+'_'+dadaEstacio.contaminant.replace('.','').replace(' ','_');\n \n if (!msg.catalogSensors.includes(sensor)) {\n sensorsToCreate.push({\n sensor,\n description: sensor,\n type,\n dataType: 'number',\n unit: dadaEstacio.unitats,\n component,\n componentType: tipusComponent,\n componentDesc: 'Estació: ' + ensInfo.nomEstacio,\n location: dadaEstacio.latitud + ' ' + dadaEstacio.longitud\n });\n msg.catalogSensors.push(sensor);\n }\n \n // Crem l'estructura de les observacions per a cada sensor (array d'observacions)\n if (!observations.hasOwnProperty(sensor)) {\n observations[sensor] = [];\n }\n \n // Format de data: 1995-01-22T00:00:00.000\n // Obtenim la data fins la T\n const dataLocal = dadaEstacio.data.substring(0,11);\n for (var h = 1; h<=24; h++) {\n const hora = ('00'+h).slice(-2);\n const hhora = ('00'+(h-1)).slice(-2);\n if (dadaEstacio['h'+hora]) {\n const isoDate = dataLocal+hhora+':00:00';\n const dateTime = DateTime.fromISO(isoDate, {zone: 'Europe/Madrid'});\n const utcTimestamp = dateTime.toUTC().toFormat(\"dd/LL/y'T'H:mm:ss\");\n // observations.get(sensor).push({\n observations[sensor].push({\n value: dadaEstacio['h'+hora],\n timestamp: utcTimestamp\n });\n }\n }\n}\n\nmsg.observationsToPublish = observations;\nmsg.sensorsToCreate = sensorsToCreate;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"luxon","module":"luxon"}],"x":650,"y":320,"wires":[["635ade89606bb2ac","36013c7c87f98676","a479600a7a957b57"]]},{"id":"6b7e658098514a7a","type":"function","z":"146cda660ffa2aa4","name":"Prepara req sentilo catalog","func":"// Estructira ensInfo = { ens: string, provider: string, token: string }\nconst ensInfo = msg.payload;\nconst provider = ensInfo.provider;\nconst token = ensInfo.token;\nconst prefixComponent = ensInfo.prefixComponent;\nconst sufixComponent = msg.sufixComponent;\nconst component = prefixComponent + sufixComponent;\n\nflow.set(ensInfo.prefixComponent+'_components', {});\n\nconst request = '/catalog/' + provider + '?component=' + component;\nmsg.url = msg.sentiloEndPoint + request;\nmsg.method = 'GET';\nmsg.headers = {\n 'identity_key': token\n}\n\nmsg.ensInfo = ensInfo;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":200,"wires":[["3f27ada6ee7681c3"]]},{"id":"a49fde2186e5add7","type":"function","z":"146cda660ffa2aa4","name":"Recupera components i sensors","func":"const ensInfo = msg.ensInfo;\nconst providers = msg.payload.providers;\n\nlet sensorsList = [];\nif (providers)\n for(var provider of providers) {\n for(var sensor of provider.sensors) {\n sensorsList.push(sensor.sensor);\n }\n }\n\nmsg.catalogSensors = [...new Set(sensorsList)];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":200,"wires":[["2882025627610752","acc86347c34d4326"]]},{"id":"2882025627610752","type":"debug","z":"146cda660ffa2aa4","name":"Sensors al catàleg","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"catalogSensors","targetType":"msg","statusVal":"","statusType":"auto","x":1010,"y":200,"wires":[]},{"id":"2d90c171e3bf88f2","type":"debug","z":"146cda660ffa2aa4","name":"Get catalog","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":160,"wires":[]},{"id":"3f27ada6ee7681c3","type":"http request","z":"146cda660ffa2aa4","name":"[GET] Catalog","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":420,"y":200,"wires":[["2d90c171e3bf88f2","a49fde2186e5add7"]]},{"id":"3519257ba59dc5f1","type":"http request","z":"146cda660ffa2aa4","name":"[GET] Data","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":410,"y":260,"wires":[["d4760a1172441dfd","4ea217a6d4ce842b"]]},{"id":"acc86347c34d4326","type":"function","z":"146cda660ffa2aa4","name":"Prepara req sentilo data","func":"// Estructira ensInfo = { ens: string, provider: string, token: string }\nconst ensInfo = msg.ensInfo;\nconst provider = ensInfo.provider;\nconst token = ensInfo.token;\n\nconst request = '/data/' + provider;\nmsg.url = msg.sentiloEndPoint + request;\nmsg.method = 'GET';\nmsg.headers = {\n 'identity_key': token\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":170,"y":260,"wires":[["3519257ba59dc5f1"]]},{"id":"635ade89606bb2ac","type":"debug","z":"146cda660ffa2aa4","name":"Sensors a crear","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"sensorsToCreate","targetType":"msg","statusVal":"","statusType":"auto","x":940,"y":320,"wires":[]},{"id":"36013c7c87f98676","type":"debug","z":"146cda660ffa2aa4","name":"Observacions a publicar","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"observationsToPublish","targetType":"msg","statusVal":"","statusType":"auto","x":970,"y":280,"wires":[]},{"id":"a479600a7a957b57","type":"switch","z":"146cda660ffa2aa4","name":"Hiha sensors per crear?","property":"sensorsToCreate","propertyType":"msg","rules":[{"t":"nempty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":170,"y":700,"wires":[["e5c78cf9062c6f6f"],["1c1151e2be7778fd"]]},{"id":"e5c78cf9062c6f6f","type":"function","z":"146cda660ffa2aa4","name":"Prepara req crear sensor","func":"const ensInfo = msg.ensInfo;\nconst provider = ensInfo.provider;\nconst token = ensInfo.token;\n\nmsg.payload = {};\nmsg.payload.sensors = msg.sensorsToCreate;\nmsg.url = msg.sentiloEndPoint + '/catalog/' + provider;\nmsg.method = 'POST';\nmsg.headers = {\n 'identity_key': token\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":640,"wires":[["a5b48427ca26db4c","1d8cd729dcc7e790"]]},{"id":"1c1151e2be7778fd","type":"function","z":"146cda660ffa2aa4","name":"Prepara dades a publicar","func":"const ensInfo = msg.ensInfo;\nconst provider = ensInfo.provider;\nconst token = ensInfo.token;\n\nconst obsToPublish = msg.observationsToPublish;\nlet sensors = {\n sensors: []\n};\n\nfor (const [sensor, observations] of Object.entries(obsToPublish)) {\n\tsensors.sensors.push({\n\t sensor,\n\t observations\n\t});\n}\n\nmsg.payload = sensors;\nmsg.url = msg.sentiloEndPoint + '/data/' + provider;\nmsg.method = 'PUT';\nmsg.headers = {\n 'identity_key': token\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":780,"wires":[["0d98eceaa533c27b","0fec41b7cd386ecd"]]},{"id":"a5b48427ca26db4c","type":"http request","z":"146cda660ffa2aa4","name":"[POST] Crear sensor","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":720,"y":640,"wires":[["5a72d69ebbbaa123","9e97401cc5f8b5e7"]]},{"id":"5a72d69ebbbaa123","type":"switch","z":"146cda660ffa2aa4","name":"Creació correcta?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":950,"y":640,"wires":[["d87bdc16cc1bdf97"],["cdc31c14b22cf471"]]},{"id":"9e97401cc5f8b5e7","type":"debug","z":"146cda660ffa2aa4","name":"Resultat crear sensors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":960,"y":600,"wires":[]},{"id":"d87bdc16cc1bdf97","type":"delay","z":"146cda660ffa2aa4","name":"Temps espera creació sensors (1m)","pauseType":"delay","timeout":"1","timeoutUnits":"minutes","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":510,"y":720,"wires":[["1c1151e2be7778fd"]]},{"id":"0fec41b7cd386ecd","type":"switch","z":"146cda660ffa2aa4","name":"Hi ha observacions?","property":"payload","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":720,"y":780,"wires":[["14f511e48a57ab83"]]},{"id":"14f511e48a57ab83","type":"http request","z":"146cda660ffa2aa4","name":"[PUT] Publica observacions","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":980,"y":780,"wires":[["842a947a31279915","3383bf95156f2540"]]},{"id":"842a947a31279915","type":"debug","z":"146cda660ffa2aa4","name":"Resultat publicar observations","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1290,"y":740,"wires":[]},{"id":"1d8cd729dcc7e790","type":"debug","z":"146cda660ffa2aa4","name":"Payload crear sensors","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":460,"y":600,"wires":[]},{"id":"0d98eceaa533c27b","type":"debug","z":"146cda660ffa2aa4","name":"Payload publicar observacions","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":490,"y":820,"wires":[]},{"id":"3383bf95156f2540","type":"switch","z":"146cda660ffa2aa4","name":"Publicació incorrecta?","property":"statusCode","propertyType":"msg","rules":[{"t":"neq","v":"200","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1260,"y":780,"wires":[["3fc8d5d663b87d54"]]},{"id":"59e17a162db99194","type":"catch","z":"146cda660ffa2aa4","name":"","scope":null,"uncaught":false,"x":100,"y":940,"wires":[["4356b5095b78ea32"]]},{"id":"4356b5095b78ea32","type":"debug","z":"146cda660ffa2aa4","name":"Catch all errors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":280,"y":940,"wires":[]},{"id":"cdc31c14b22cf471","type":"debug","z":"146cda660ffa2aa4","name":"Finalitza error creació sensors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1290,"y":640,"wires":[]},{"id":"3fc8d5d663b87d54","type":"debug","z":"146cda660ffa2aa4","name":"Finalitza error publicació observacions","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1310,"y":820,"wires":[]}]