Archivo de la categoría: Programación

Simular el posicionamient GPS (problemas en el despliegue a la nube, OVH)

Tenemos una REST API con MongoDB. Tenemos un front-end para generar posiciones y grabarlas en la bd. Y tenemos otro front-end para visualizar las posiciones y ver cómo van evolucionando.

La parte de generar las posiciones y enviarlas al servidor de momento no es una aplicación móvil, sino que es una página web. Openlayers tiene la posibilidad de hacer geolocation, y por tanto tenemos una precisión muy buena (unos 15 m). No es necesario por tanto una aplicación móvil. Ahora bien, hay que hacerlo con https.

(ref): https://stackoverflow.com/questions/39366758/geolocation-without-ssl-connection:

Warning by Chrome : getCurrentPosition() and watchPosition() no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS.

Hasta aquí ningún problema especial cuando se desarrolla localmente (localhost). Pero el problema esté cuando se despliega en el servidor, en este caso un VPS en OVH. Por tanto, la parte de generar las posiciones GPS tiene que ir al servidor OVH donde hay instalado el certificado SSL. Ahora bien, no se pueden generar certificados para el dominio ovh.net con noip.com (se han pasado de la cuota, lógico). Así pues, primero me he tenido que registrar en noip.com y ahora tengo el dominio jquintana.ddns.net.

Poner el MongoDB en el servidor no ha sido ningún problema. El problema está en la API REST, hecha con Express. La API REST se ha tenido que hacer segura (https), pues no podía ser que llamásemos a la API desde https, y que este servidor respondiese com http. Este ha sido el problema principal.

Finalmente la parte del front-end de visualizar las posiciones no ha tenido especial problema. Las llamadas a la API http://localhost:3000 se han de cambiar a les llamadas a la API https://jquintana.ddns.net:8080.

En resumen, tú puedes tener una aplicación funcionando con localhost sin especiales problemas, y cuando la quieres desplegar en la nube empiezan los problemas de CORS, seguridad, protocolos que no te habías planteado.

Ahora el último paso es tener un código que funcione igual de bien en localhost y en la nube, que esto en principio no será problema. Y la reflexión es que cuando se desarrolla un proyecto, no hay que esperar al final de tot para desplegarlo a la infraestructura de la nube. Hay que hacerlo ya en las primeras fases: es el despliegue continuo. Aunque la aplicación no tenga muchas funcionalidades, ya se ha podido afrontar todos los problemas de seguridad e infraestructura al intentar desplegar en un entorno real en las primeras fases. Y así nos ahorramos problemas al final del proyecto.

Programando el tracking de rutas

Programando casa-insitutoAyer por la noche estaba programando, y estaba grabando posiciones simuladas desde casa. Como en casa no me muevo, tuve que simular cierto movimiento. Los datos se graban en una base de datos MongoDB.

Hoy estaba continuando un rato, desde el instituto, y voilà, hay un salto desce casa al instituto. Lógico pero divertido.

Openlayers: Point, LineString, MultiLineString, Icon. Ejemplo canónico

Ejemplo canónico OpenlayersVamos a mostrar un ejemplo mínimo de Openlayers que aclare los conceptos de dibujar un punto, una línea, una multilínea y un icono. Y cómo aplicar estilos a estos elementos.

Definimos primero estos elementos (puntos, líneas, multilíneas, iconos) a partir de los datos de ejemplo (coordenadas). Entonces definimos features a partir de estos elementos, que aañadimos a un array de features. Cada feature puede tener su estilo.

Definimos después el vectorSource a partir del array de features. Después definimos el VectorLayer a partir del vectorSource. Y finalmente añadimos al mapa los layers que queremos pintar.

Este es el codi inicial y previo para un pequeño proyecto que quiero hacer, que se trata de una aplicación mòvil para enviar las coordenadas de posición a una RestAPI donde hay una base de datos (MongoDB), y con una aplicación web (front-end, que es la part que aquí se empieza a explicar) poder visualizar el recorrido del ciclista (la idea del proyecto es poder hacer el tracking de un ciclista en una primera etapa; y en una etapa posterior poder hacer el tracking de todos los ciclistas que participan en una carrera o salida).

El código final:

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Icon, Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style';
import {LineString, MultiLineString, Point} from 'ol/geom';
import {getVectorContext} from 'ol/render';
import {fromLonLat} from 'ol/proj';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import OSM from 'ol/source/OSM';

//dades
var json_points = [
{'lon':1.4234,'lat':41.2344,'name':'punt 0'},
{'lon':1.4235,'lat':41.2345,'name':'punt 1'},
{'lon':1.4235,'lat':41.2346,'name':'punt 2'},
{'lon':1.4236,'lat':41.2346,'name':'punt 3'},
{'lon':1.4236,'lat':41.2347,'name':'punt 4'},
{'lon':1.4238,'lat':41.2349,'name':'punt 4'},
{'lon':1.4239,'lat':41.2350,'name':'punt 4'}
];

// estils
var styles = {
'Point': new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(100,100,100,.8)',
}),
radius: 3,
stroke: new Stroke({
color: '#000000',
width: 2,
}),
}),
}),
'LineString': new Style({
stroke: new Stroke({
color: '#f00',
width: 3,
}),
}),
'MultiLineString': new Style({
stroke: new Stroke({
color: '#000000',
width: .8,
}),
}),
'icona': new Style({
image: new Icon({
anchor: [0.5,20],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'img/circle_red_8.png'
})
})
};

// points
var features_points = new Array();

var feature_point0 = new Feature({
'geometry': new Point(fromLonLat([json_points[0].lon,json_points[0].lat])),
'name': json_points[0].name,
});

var feature_point1 = new Feature({
'geometry': new Point(fromLonLat([json_points[1].lon,json_points[1].lat])),
'name': json_points[0].name,
});

var feature_point2 = new Feature({
'geometry': new Point(fromLonLat([json_points[2].lon,json_points[2].lat])),
'name': json_points[0].name,
});

var feature_point3 = new Feature({
'geometry': new Point(fromLonLat([json_points[3].lon,json_points[3].lat])),
'name': json_points[0].name,
});

var feature_point4 = new Feature({
'geometry': new Point(fromLonLat([json_points[4].lon,json_points[4].lat])),
'name': json_points[0].name,
});

features_points.push(feature_point0)
features_points.push(feature_point1)
features_points.push(feature_point2)
features_points.push(feature_point3)
features_points.push(feature_point4)

// línies
//Create a feature and add geometry as a thing
var track1 = new MultiLineString([
[[json_points[0].lon,json_points[0].lat],[json_points[1].lon,json_points[1].lat]],
[[json_points[1].lon,json_points[1].lat],[json_points[2].lon,json_points[2].lat]],
[[json_points[2].lon,json_points[2].lat],[json_points[3].lon,json_points[3].lat]],
[[json_points[3].lon,json_points[3].lat],[json_points[4].lon,json_points[4].lat]]
]).transform('EPSG:4326','EPSG:3857');

var feature_multilinestring = new Feature({
geometry: track1,
name: 'nom track 1'
});

var line1 = new LineString([
[json_points[5].lon,json_points[5].lat],[json_points[6].lon,json_points[6].lat]
]).transform('EPSG:4326','EPSG:3857');

var feature_linestring = new Feature({
geometry: line1,
name: 'nom línia 1'
});

var features_strings = new Array();

features_strings.push(feature_multilinestring)
features_strings.push(feature_linestring)

//icones
var features_icones = new Array();

let feature_icona1 = new Feature({
geometry: new Point(fromLonLat([json_points[5].lon,json_points[5].lat])),
name: 'Inici',
});

let feature_icona2 = new Feature({
geometry: new Point(fromLonLat([json_points[6].lon,json_points[6].lat])),
name: 'Final',
});

feature_icona1.setStyle(styles.icona); //no cal si defineixo el estil en el layer.
feature_icona2.setStyle(styles.icona); //però definiré l'estil en la icona si cada icona ha de tenir un estil diferent

features_icones.push(feature_icona1);
features_icones.push(feature_icona2);

// vectorSources
var vectorSourcePoints = new VectorSource({
features: features_points,
wrapX: false,
});

var vectorSourceStrings = new VectorSource({
features: features_strings,
wrapX: false,
});

var vectorSourceIcones = new VectorSource({
features: features_icones,
wrapX: false,
});

// layers
var layerPoints = new VectorLayer({
source: vectorSourcePoints,
style: styles.Point,
});

var layerStrings = new VectorLayer({
source: vectorSourceStrings,
style: styles.MultiLineString,
});

var layerIcones = new VectorLayer({
source: vectorSourceIcones,
style: styles.icona,
});

var map = new Map({
layers: [
new TileLayer({
source: new OSM({
layer: 'OSM'
})
}),
layerPoints,
layerStrings,
layerIcones
],
target: 'map',
view: new View({
center: fromLonLat([1.4234, 41.2344]),
zoom: 18
})
});

BDQuest: Quests para el lenguaje SQL

Este año hago en 1º de DAM la M02, Bases de Datos. Siempre he trabajado con bases de datos, con los alumnos, pero esta asignatura hacía mucho tiempo que no la hacía.

En verano me animé a hacer una herramienta web para que los alumnos pudiesen testear sus sentencias SQL de forma automática, y que también fuese un recurso para evaluar y auto-evaluar. Esta aplicación es BDQuest, el nombre no es muy original, pero a estas alturas ya no me atrevo a cambiarlo.

Empezamos el curso y en la UF1 no se hace nada de SQL. Pero en la UF2, que es la troncal del curso y que ya estamos acabando, los alumnos han estado utilizando la herramienta, y así poder practicar selects básicas, inserts, updates, deletes, create, alter y drop tables, create y drop views, selects complejas, etc.

Los alumnos han hecho de conejitos de indies y la versión 10, que es la actual, la he ido actualizando a lo largo del trimestre. ¡Y funciona muy bien!

Y ahora que estamos acabando la UF2 y no falta nada para empezar la UF3, he adaptado la aplicación para poder hacer create y drop users, grant privilegios, etc; y también create procedures, etc. Y los triggers ya vendrán. Es decir, que el objetivo inicial de que no sólo sirviese para hacer selects se habrá cumplido de sobras.

Hasta ahora no había escrito nada ni aquí ni en la wiki. Ya es hora de documentar un poco el proyecto y darlo a conocer. A ver si alguien le puede sacar provecho.

A la aplicación todavía le faltan muchas cosas, pero lo importante es que este año ha sido funcional. Es una típica aplicación web con mucho de Javascript y PHP-MySQL, y con un diseño de momento minimalista. La aplicación tendría que crecer por aquí: mejorar el diseño; y utilitzar algún framework en el lado del cliente y del servidor. Y también alguna refactoritzación del código y mejora de unas cuantas cosas.

CatGeoQuest: aplicación para hacer tests de geografía

En esto estoy estos últimos días. Me he dado prisa para poder hacer una demo que se pueda enseñar y que ya sea jugable.

Tengo muchas ideas relacionadas con esta aplicación, puede crecer bastante. Lo que todavía no tengo claro es si le pondré una capa de back-end con bases de datos, o lo dejaré como una SPA (Single Page Application) con sólo front-end y Javascript.

He intentado sacar el máximo provecho de la librería de Openlayers y, como siempre, me ha dado algún quebradero de cabeza pero también he aprendido bastante por el camino. Ahora que ya tengo una versión jugable, el camino para continuar será más plácido y tranquilo…

Paraulògic

Hace días que todo el mundo por aquí Catalunya va detrás de esta aplicación del Paraulògic, para encontrar palabras en catalán que están en el diccionario DIEC (el diccionario del Institut d’Estudis Catalans.

A partir de un tweet de hoy se ha puesto en evidencia la sencillez de la aplicación web, todas las palabras del día están en el código html y en texto plano. Pensaba que la aplicación se conectaría a alguna API del diccionario del DIEC (sería muy interesante que existiese esta API y que fuese de acceso libre).
Però no, la cosa es mucho más sencilla: todas las palabras del día se pueden ver haciendo el típico Ctrl-U (Ver código fuente), y allá tienes todas las palabras sin codificar, y de esta manera es muy sencillo tener la máxima puntuación y poderte lucir delante de la gente y de los familiares. Lo que se puede hacer para evitarlo es una encriptación fácil con Base64, almenos para ponerlo un poco más difícil a los curiosos del html.

Lástima que las vacaciones de Navidad ya se han acabado y ya no podremos dedicar más tiempo a esto del Paraulògic

rutesgps, versión 16

Aquí una nueva versión de rutesgps.joanillo.org, implementando unas pocas opciones que tenía ganas de hacer:

  • Cada excursión tiene una url que la identifica. Por ejemplo, la última ruta que he hecho: Igualada-Calaf-Manresa-Igualada: igualada-manresa-igualada
  • Un botoncito para copiar directamente el enlace de la excursión.
  • He añadido dos markers, para que quede claro dónde comienza y dónde acaba la excursión.

Referencies:

RutasGPS: implementación del buscador de rutas

Una nueva versión de rutesgps.joanillo.org. Hay dos mejoras que hace tiempo que quería implementar. Primero, que las rutas estén ordenadas alfabéticamente. Segundo, la implementación de un buscador de rutas, pues ahora ya hay bastantes y era necesario.

Esta es una app totalmente Javascript. No hay nada de BD ni PHP. Todo es Javascript y JSON, y los contenidos y los mapas se generan dinámicament.

Bot de Twitter sobre reavivar el catalán

Empieza un nuevo curso, y proyectos nuevos. Durante 10 años he estado recopilando información de palabras que me gustan, y que están cayendo en desuso. Además, el escritor Jordi Badia acaba de publicar el libro Salvem els Mots que precisamente va sobre esta problemática.

Ya hacía tiempo que me rondaba hacer un bot de Twitter. Así pues, lo que he hecho es coger la información que tengo, y estructurarla en una base de datos (recordemos: información > conocimiento). Y utilizando el paquete Tweepy de Python, y registrándome en Tweeter como desarrollador, después de un proceso más o menos rápido, ya tengo mi bot de Twitter en marcha.

Se trata de moment de enviar un mensaje cada dos días, con un contenido humorístico y picante, relacionado con palabras y expresiones del catalán que nos gustaría recuperadas y normalizadas. La cuenta de Twitter es @CatalaRevifat

Referencias:

RutasGPS, nueva versión

Se ha publicado la nueva versión de mis rutas en bici. De la v5 a la v7 hay muchos cambios significativos: cambio total del diseño, responsive, Javascript con módulos, Openlayers v6 en la parte de mapas, se ha eliminado toda la parte de PHP (ahora es una webapp).

La lista de rutas se había hecho muy larga, y por tanto ahora las rutas se agrupan por zonas geográficas, que es un desplegable. Podemos filtrar por las rutes que se han hecho, y distinguirlas de las rutas ToDo, que son las que queremos hacer próximamente, si todo va bien. Las capas de render que se han escogido son el estandard de OSM, el TOPOTRESC, la OrtoFoto del ICGC, y el estandard del ICGC.
La única funcionalidad que queda por implementar es la Búsqueda de rutas, a ver si lo puedo hacer antes de las vacaciones.

Todo el código está colgador en el github. En la foto se puede apreciar el cambio de diseño de la versión anterior a la actual. Otra mejora importante que se ha implementado es la automatización del despliegue al servidor, de manera que ahora es más fácil y está más documentado publicar los cambios en la nueva versión.

Referencias: