msgbartop
¡Mano de milenio y gamba!
msgbarbottom

07 feb 21 Cómo registrar información de The Things Network en una hoja de cálculo de Google Spreadsheet

Llevo algún tiempo trabajando con redes LoRa y LoRaWAN, tanto en temas de trabajo, como finalmente desde el punto de vista profesional. En este último ámbito voy a tener que hacer un estudio de cobertura de una red LoRaWAN para uno de nuestros clientes: la idea es registrar una serie de parámetros de los equipos que se van a instalar en una planta de producción, para lo que es necesario determinar los puntos más adecuados para instalar los gateways que encaminarán la información de los dispositivos. Todo esto implica recorrerse la planta, realizando pruebas de ubicación de los mismos y registrar estos parámetros.

Para ello voy a utilizar, dado que la red LoRaWAN del cliente aún no está constituida, la red The Things Network, que ofrece toda la información que necesito. Sin embargo, la red TTN es una red de transporte, y aunque muestra la información que necesito, no la consolida. Al fin y al cabo se trata de eso, de transportar. El tema del almacenaje ha de realizarse por otro lado. Podría apuntar estos valores a mano, pero he encontrado una manera más divertida de realizarlo: registrar los parámetros y la información de la red con Google Spreadsheet. Ojo, este mecanismo está muy bien para pruebas preliminares y análisis como el que estoy buscando, pero no debe ser usado en un entorno en producción, ya que no se establecen (es más, se eliminan) mecanismos de seguridad de las comunicaciones o de la información alguno.

El artículo que enlazo explica perfectamente cómo hacerlo, pero dejo aquí los pasos generales:

  • Crear una hoja de cálculo en Google Spreadsheet, y ponerle un nombre (ojo, tanto al documento como a la hoja en sí) descriptivo.
  • Ir a Herramientas > Editor de secuencias de comandos, e introducir el código que se adjunta:


// 2017 by Daniel Eichhorn, https://blog.squix.org
// Inspired by https://gist.github.com/bmcbride/7069aebd643944c9ee8b
// Create or open an existing Sheet and click Tools > Script editor and enter the code below
// 1. Enter sheet name where data is to be written below
var SHEET_NAME = "Sheet1";
// 2. Run > setup
// 3. Publish > Deploy as web app
// - enter Project Version name and click 'Save New Version'
// - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)
// 4. Copy the 'Current web app URL' and post this in your form/script action

var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service

// If you don't want to expose either GET or POST methods you can comment out the appropriate function
function doGet(e){
return handleResponse(e);
}

function doPost(e){
return handleResponse(e);
}

function handleResponse(e) {
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.

try {
// next set where we write the data - you could write to multiple/alternate destinations
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
// we'll assume header is in row 1 but you can override with header_row in GET/POST data

//var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];

var nextRow = sheet.getLastRow()+1; // get next row
var row = [];
var headerRow = [];
// loop through the header columns
var jsonData = JSON.parse(e.postData.contents);

headerRow.push("jsonData.app_id");
headerRow.push("jsonData.dev_id");
headerRow.push("jsonData.hardware_serial");
headerRow.push("jsonData.port");
headerRow.push("jsonData.counter");
headerRow.push("jsonData.payload_raw");
headerRow.push("jsonData.payload_decoded");
headerRow.push("jsonData.metadata.time");
headerRow.push("jsonData.metadata.frequency");
headerRow.push("jsonData.metadata.modulation");
headerRow.push("jsonData.metadata.data_rate");
headerRow.push("jsonData.metadata.coding_rate");
headerRow.push("jsonData.metadata.downlink_url");
for (var i = 0; i < jsonData.metadata.gateways.length; i++) {
var gateway = jsonData.metadata.gateways[i];
headerRow.push("gateway.gtw_id");
headerRow.push("gateway.timestamp");
headerRow.push("gateway.channel");
headerRow.push("gateway.rssi");
headerRow.push("gateway.snr");
headerRow.push("gateway.latitude");
headerRow.push("gateway.longitude");
headerRow.push("gateway.altitude");
}
sheet.getRange(1, 1, 1, headerRow.length).setValues([headerRow]);

row.push(jsonData.app_id);
row.push(jsonData.dev_id);
row.push(jsonData.hardware_serial);
row.push(jsonData.port);
row.push(jsonData.counter);
row.push(jsonData.payload_raw);
var raw = Utilities.base64Decode(jsonData.payload_raw);
var decoded = Utilities.newBlob(raw).getDataAsString();
row.push(decoded);
row.push(jsonData.metadata.time);
row.push(jsonData.metadata.frequency);
row.push(jsonData.metadata.modulation);
row.push(jsonData.metadata.data_rate);
row.push(jsonData.metadata.coding_rate);
row.push(jsonData.metadata.downlink_url);
for (var i = 0; i < jsonData.metadata.gateways.length; i++) {
var gateway = jsonData.metadata.gateways[i];
row.push(gateway.gtw_id);
row.push(gateway.timestamp);
row.push(gateway.channel);
row.push(gateway.rssi);
row.push(gateway.snr);
row.push(gateway.latitude);
row.push(gateway.longitude);
row.push(gateway.altitude);

}

// more efficient to set values as [][] array than individually
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e) {
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}

function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
}

  • Ejecutar la función "setup" mediante Ejecutar > Ejecutar función > Setup. Indicar los permisos adecuados para acceder a la hoja de cálculo creada anteriormente.
  • Publicar el script mediante Publicar > Implementar como aplicación web. Crear un nombre de versión descriptivo, indicar que el nivel de seguridad para ejecutar la aplicación será "Yo", e indicar que el acceso a la aplicación será para "Cualquiera, incluso anónimo" (a esto me refería con la seguridad de la información más arriba).
  • Copiar la URL de la aplicación web que nos genera.
  • Posteriormente, en la consola de TTN, será necesario añadir a nuestra aplicación una integración de tipo HTTP, creando un Process ID significativo, indicar la Access Key como "default", añadiendo la URL que hemos copiado anteriormente, e indicándo que el método HTTP a utilizar será "POST".

Y con esto, la información generada por nuestros dispositivos LoRaWAN registrados en TTN pasará a almacenarse de manera automática en nuestra hoja de cálculo:

Datos LoRaWAN en Google Spreadsheet

Datos LoRaWAN en Google Spreadsheet

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , ,

07 feb 21 Etapa ciclista: Forcarey – Quintillán – A Lagoa – Castro de Muras (06/02/2021)

No tardé mucho en estrenar la nueva horquilla Rock Shox Recon que comentaba ayer. A las 9:30h de la mañana del sábado estaba ya rondando para realizar su recorrido inaugural. Salí con 4ºC y una ligera llovizna, que me acompañó -por suerte- solo durante los primeros kilómetros de la etapa. Salí de Forcarey por un camino junto al cementerio, que me llevó en primer lugar a una antena de telecomunicaciones que hay en el pueblo, y posteriormente hasta las cercanías de Las Casetas. En teoría el camino, que transcurre en paralelo a la carretera de La Estrada, tendría que haberme conducido hasta la carretera de Rozados, pero aproximadamente a la mitad, cerca de la estación de servicio, se encontraba completamente obstruido de tojos y espinos, así que no me quedó más remedio que desviarme a la carretera. Desde allí, una vez llegado a la altura del concesionario de coches, me desvié a la derecha por la carretera de Rozados. Seguí un rato por ella, hasta una pista que baja entre eucaliptos hasta la cascada de Quintillán. Una verdadera preciosidad, de la que ya nos habían comentado hace algún tiempo. Paré un rato para tomar unas fotos y vídeos, que comparto a continuación.

IMG_20210206_100804037
IMG_20210206_100446810
IMG_20210206_100717478
IMG_20210206_100457391

De nuevo en marcha, tomé la carretera para subir hasta Quintillán, si bien me desvié antes de llegar al casco urbano, por el camino del cementerio. Seguí en dirección norte por un viejo camino asfaltado, camino de mi siguiente parada: la ermita en ruinas de San Amaro. Este camino forma parte de la Ruta de los Arrieros, y probablemente de una vieja calzada romana que se puede seguir hasta Santiago.

IMG_20210206_102143283_HDR
IMG_20210206_101752418_HDR
IMG_20210206_101909707
IMG_20210206_102031629

La ermita se encuentra en un meandro sobre el río Umia, habiendo cerca de la misma un pequeño azud, que crea una represa y un salto de aguas que espero disfrutar este verano. :mrgreen:

Dejada atrás la ermita, se llega al punto más bajo del recorrido: el vado del río Umia. Desde aquí, queda un rato interesante de subida. En primer lugar, se pasa por los núcleos de A Rúa, O Barrio y Seoane, desde donde se toma una carretera hacia el este, que se abandona, a mano izquierda, al llegar al cementerio. Se sigue un rato por carretera hasta llegar, 1km después, a una pista que surge en fuerte subida a mano izquierda. Una pista de tierra amarillenta, que se agarra al neumático como si el mañana no existiera. Esta pista, tras 2’5km, y tras varios cambios de dirección, cruces, y tipo de firme, acaba llegando a la aldea de Los Campos. Desde allí se divisa una vista estupenda del valle del Lérez y de la Sierra de Cando.

IMG_20210206_110700497_HDR

Se sale de la aldea por una pista junto a la ermita que, en ascenso, asciende hasta los campos cercanos a la Laguna Sacra de Olives, las Brañas de Xestoso. Aparte de por la laguna en sí, que es un espectáculo por sí sola, cabe la pena destacar que la zona contiene las turberas ácidas de toda Galicia, lo que se deja observar en la carencia de grandes árboles, como los que venían acompañándome durante todo el trayecto, para dejar paso a una vegetación arbustiva baja. Solía decir que esta zona se parecía una barbaridad a las Colinas Wicklow de Dublín, salvo por la ausencia de turberas. Ya no lo puedo decir.

IMG_20210206_112011730_HDR

Pasada la Laguna, se gira hacia el este, tomando una carretera que lleva a Xestoso, pero en mi caso, tomé un desvío a mano derecha, para (casi) volver sobre mis pasos, girando al sur en una serie de caminos embarrados que me habrían de llevar -en falso llano pero en general descendiendo- hasta Castro de Muras. Se notaba, sobre todo al principio, que era zona de turberas. Me estaba poniendo hasta arriba de fango negro.

IMG_20210206_113103623_HDR

Se llega a Castro de Muras en un divertido descenso por pista, que nos devuelve al río Umia, junto al que hay algunos estupendos ejemplos de molinos, con sorprendentes acequias para encauzar el agua hasta ellos, o bien ubicados directamente sobre el cauce.

IMG_20210206_115214387_HDR
IMG_20210206_115752461

Para llegar a Castro de Muras hay que iniciar un nuevo ascenso, que ya no parará hasta llegar a la Forca da Loba y el Coto Vello, que constituyen la cota máxima de la etapa (704msnm). Desde allí se hace un divertido descenso por pista hasta llegar a la carretera de Rabadeieras, desde donde se vuelve a enlazar con Las Casetas. Mi idea inicial era bajar por Las Rabadeiras hasta Córneas, y desde allí subir por otra pista que lleva al cementerio de Forcarey, pero volvía a llover un poco, y decidí acortar la etapa. Sin embargo, no pude resistirme a intentar el primer camino de la mañana, pero entrando esta vez por arriba. No duré mucho por él: unas enormes balsas de agua me dejaron clavado, y tuve que echar pie a tierra para cruzarlas. Llegados a una plantación de eucalipto el camino se desvía a la izquierda, pero por error seguí de frente hasta llegar a una finca sin salida. En vez de dar la vuelta, y dado que la finca presentaba una puerta a la carretera de Forcarey, decidí dar la etapa por finalizada y volver por carretera, dejándome caer -por una vez- y llegando a Forcarey en descenso, tras un total de 30’010km de etapa. Un más que buen estreno para la Recon, que además se portó de lujo.

Datos de la etapa

  • Distancia: 30’010km
  • Distancia (según el GPS): 30’01km
  • Altitud ascendida: 545m
  • Tiempo de etapa: 2:23:36
  • Tiempo desde el inicio de la etapa: 3:06:01
  • Calorías consumidas: 2806kcal

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , , , , ,