O, para los que quieren saber de qué vamos a hablar aquí, de cómo usar los tuneles de cloudflare para exponer una web al mundo que está corriendo en uno de nuestros ordenadores (sin IP fija ni nada).
Supongamos que acabamos de crear nuestra aplicación (o todavía la estamos creando) y queremos enseñársela al mundo (o a nuestro cliente, que para el caso es lo mismo). Hasta ahora, si no teníamos una IP fija lo más habitual era tener que subir todo a un hosting (más caro o más barato) e ir actualizando allí el código cada vez que hacíamos algún cambio.
Cuando queramos pasar a producción una web con miles de millones de accesos (sic.) pues probablemente no nos importe gastarnos el dinero en un hosting decente, o instalarnos en la nube (AWS, GCE o Azure), pero para hacer experimentos o para ejecutar cosas en nuestra casa esto no hace falta… Y menos si tenemos en cuenta que hay opciones gratuitas para evitarlo.
Vayamos al tajo… Imaginemos que tenemos un ordenador donde estamos trabajando y que tiene la IP 192.168.1.35 y que, obviamente, podemos ver nuestra web en http://localhost (desde nuestro propio ordenador) o desde http://192.168.1.35 desde cualquier otro ordenador de nuestra casa. Supongamos también que hemos comprado un dominio «undominio.org» por ejemplo.
Lo siguiente será crear una cuenta en cloudflare, simplemente accedemos a cloudflare.com y nos registramos, una vez registrados damos de alta el dominio que tenemos (probablemente tendremos que cambiar los dns en nuestro proveedor de dominios, a no ser que lo hayamos comprado en el mismo cloudflare) y cuando nos informe de que ya estamos administrando el dominio podemos empezar con la parte del tunel… Para ello vamos a seleccionar Zero Trust en el panel de la izquierda:
Y esto nos dará acceso (si te pide datos de tarjeta no te preocupes, puedes seleccionar el plan gratuito y no se te cobrará nada) terminarás en esta pantalla:
Ahora seleccionamos redes-> tunnels
Y damos al botón crear nuevo tunel. Nos dará dos opciones y seleccionamos Cloudflared
Nos pedirá asignar un nombre al tunel y luego nos da las opciones para instalar cloudflared. Tienes que seleccionar el sistema operativo en el que tienes la web corriendo y la arquitectura. En mi caso lo tengo corriendo en un linux, así que simplemente tengo que copiar el código y ejecutarlo en una consola:
Una vez instalado y puesto a funcionar en nuestra máquina local, nos aparecerá en la lista de conectores:
Ahora toca elegir un subdominio o ruta para publicar nuestra web y la url local donde se encuentra la web (en mi caso estoy publicando la web de inteligencia artificial que ya montamos en uno de los posts anteriores:
Y con esto ya tenemos publicada la web en https://ia.undominio.org sin haber salido de nuestro ordenador…
La verdad es que esto del Zero trust tiene muchas más utilidades además de los túneles, no dejes de revisar todas las cosas interesantes que se pueden hacer (como verás hasta te has ahorrado el tema de los certificados y demás…)
Así que, ya sabes, anímate a publicar en internet lo que quieras sin tener que migrarte a la nube…
Si tienes aire acondicionado, uno de los defectos que más se encuentran en estos aparatos es cómo deshacerse del agua de condensación del mismo, especialmente en verano. Si eres como yo o como la mayoría de la gente, lo que harás será poner una botella en algún sitio accesible que se va llenando poco a poco y que, periódicamente, tendrás que cambiar para que no se desborde. Pero, en tiempos calurosos y ajetreados es muy común que la botella (sea del tamaño que sea) termine llenándose y mojemos a quien sea que tengamos debajo del aire acondicionado.
Esta dinámica, que a mi se me antoja muy molesta, la llevo repitiendo en casa y en la oficina (si, en mi oficina tengo un aire acondicionado con botellita) durante varios años y siempre me planteo, ¿y si hago algo para que me avise justo cuando está apunto de llenarse y así puedo cambiarla a tiempo? Hasta el momento no había tenido tiempo, pero ahora he encontrado un ratillo y me he puesto manos a la obra.
Los requisitos eran sencillos, necesito saber si el nivel de agua de una botella ha llegado a cierta altura en la botella, no necesito saber el % exacto, pero si saber si se esta llenando antes de que se llene. Hay algunos sensores de ultrasonidos para depósitos, pero me parecía matar moscas a cañonazos, además, el tamaño de la botella podía ser variable, por lo que el sensor no tendría que ser muy aparatoso. Buscando encontré este:
Puede funcionar a 3.3v o 5v y básicamente devuelve un valor analógico distinto según por donde le llegue el agua en la parte inferior. Este es el enlace de compra en amazon: https://www.amazon.es/dp/B07DJ5FZ31
Por otro lado quería que la solución fuese portable, es decir, que no tuviese que andar echando cables por ahí, por lo que una solución que admitiese baterías también era recomendable. Como plataforma yo estoy muy acostumbrado a usar ESP32 y me hacía mucho más sencillo la parte de conexión a la wifi, así que buscando encontré esto:
Un ESP32-C3 que tiene un puerto para batería que se puede recargar mediante usb, me fue casi más complicado hacerme con las pilas LS16340
Con todos los componentes solo me quedaba conectar el ESP32-C3 al sensor, teniendo cuidado de no usar el pin que se usa para medir el voltaje de la pila (spoiler, es el A0 y lo descubrí después de haberlo soldado). El esquema sería tal que así:
Todo soldado para probar quedaría así:
Y ahora lo interesante, que sería programarla para que podamos controlar el nivel de agua. Como las especificaciones no son siempre exactas lo que hice fue unas pruebas leyendo el nivel del GPIO04 (que tiene conversor A/D) y meter y sacar el sensor del agua imprimiendo por el puerto serie los valores obtenidos:
#define A1 4
void setup() {
// (Optional)Press reset button
// on the dev board to see these print statements
Serial.begin(115200);
while (!Serial) { }
// Configuramos el pin A1 como de entrada analógica
pinMode(A1, INPUT);
delay (1000);
Serial.println("Starting...");
}
void loop() {
int sensorValue = analogRead(A1);
Serial.println(sensorValue);
delay(1000);
}
Nota: Esto lo he compilado usando platformio.io (os lo recomiendo mucho) y os dejaré el proyecto completo en un repositorio para que podáis compilarlo vosotros también.
Una vez compilado e instalado el programa veíamos por el puerto serie cada segundo el valor que leíamos del sensor, obteniendo valores entre cero y 3000 (supongo que el rango máximo será Vin que en nuestro caso es 3.3v), así que nuestro valor «umbral» será de 2000 (no se ha llegado todavía arriba del todo pero ya hay agua mojando el sensor).
El siguente paso es conectar a internet para que nos pueda mandar la alerta. Esto en ESP32 es relativamente sencillo:
#include <WiFi.h>
void printWifiStatus() {
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
boolean connectWifi (char *ssid, char *pass){
WiFi.useStaticBuffers(true);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
int max = MAXATTEMPS;
Serial.println("Connecting to WiFi");
while ((WiFi.status() != WL_CONNECTED) && --max>0) {
delay(500);
Serial.print(".");
}
if (max == 0)
return false;
Serial.println("Connected to WiFi");
return true;
}
Con esto solo hay que añadir una llamada a connectWifi parándole el SSID y la contraseña de nuestra red wifi para tener conexión. Una vez que tenemos conexión podemos hacer varias cosas para hacernos llegar una alerta, pero la más sencilla para mi era hacer que me enviase un mensaje por telegram. Para ello habría que crear un bot (hablando con botfather) y obtener el token necesario para poder usarlo. Luego he creado un canal y he puesto a este bot como administrador, con lo que para utilizar este bot solo tendría que hacer estos defines:
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
WiFiClientSecure client;
UniversalTelegramBot bot(BOTTOKEN, client);
client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
bot.sendMessage(CHAT_ID, "esto es un mensaje");
Así que la lógica del programa cambia ahora a que cuando el valor detectado sea mayor que 2000 enviemos un mensaje con el bot para alertarnos.
El programa lo he mejorado para leer el valor de voltaje de la batería y para que entre en suspensión y se despierte cada 10 segundos para ahorrar energía, pero eso podéis sacarlo de los ejemplos que hay en el repositorio https://github.com/Xinyuan-LilyGO/LilyGo-T-OI-PLUS. El caso es que ahora tenía que hacer el montaje final en mi botella de agua del aire acondicionado. Elegí un bote de estos gigantes de proteinas (si, alguien en casa va al gimnasio) y tras impermeabilizar adecuadamente los cables y las conexiones decidí meter el sensor por la parte superior del tapón y así antes de llegar arriba del todo haría el contacto adecuado y quedó tal que así:
Y ya con el tubo del aire metido y todo:
Si queréis ver el resultado final (probando con una taza con agua, que no voy a esperar que se llene el bidón este) os dejo aquí un video:
Tengo que reconocer que con el advenimiento de chatGPT y las muestras de la IA generativa en campos como la programación de un tiempo a esta parte las expectativas se han disparado con respecto a lo que se puede esperar de una Inteligencia Artificial. Sin embargo, no es oro todo lo que reluce.
La disciplina de Inteligencia Artificial existe desde hace muchísimos años, yo mismo, como estudiante de mi facultad fui miembro del Laboratorio de Inteligencia Artificial desde el año 1989 hasta que salí del mismo (esa es una historia para contar en otro momento) y me dediqué a otros proyectos de IA como la traducción automática. Pero la IA es anterior a estas fechas incluso. La verdad es que el avance «real» de la IA no ha sido expectacular estos años pasados excepto en la imaginación de algunos autores de ciencia ficción.
¿Porqué, entonces, se ha notado un avance tan importante estos últimos años? Bueno, lo que yo os puedo decir es que no toda la IA ha avanzado por igual, la que ahora mismo disfutamos es la IA generativa basada en aprendizaje profundo «Deep Learning». Para que se entienda, se trata de un sistema que «aprende» en base a miles de millones de muestras a generar «algo», una imagen, un texto, una respuesta ante una entrada determinada. Y el problema está en que al utilizar esa IA simplemente estamos recombinando los elementos de su entrenamiento de manera que sea más o menos adecuado a la pregunta o solicitud de entrada, no hay lógica, no hay algoritmo, es simple aprendizaje.
Si tu le preguntas algo a chatGPT no se desencadenan procedimientos lógicos que luego se puedan auditar, lo que se produce es una generación de lo que más probablemente, según los documentos que ya aprendió, se parezca a una respuesta a esa pregunta. Lo más parecido a un papagayo al que se le han enseñado miles de frases, te dará una respuesta tenga ésta sentido o no lo tenga.
De hecho, uno de los efectos más curiosos de las IAs generativas es que se inventan cosas – «alucinaciones» -, y no hay forma de que sepan si es cierto o no lo que están contando, por lo que es complicado, por no decir imposible, fiarse al 100% de lo que podamos obtener de una IA de este estilo. A diferencia de las imágenes que ilustran esta entrada, que han sido generadas por IA y podemos verlas como una simple muestra más o menos estética, si hacemos caso de lo que nos recomienda chatGPT, Gemini o cualquier otra AI generativa estaremos haciendo caso a un papagayo con mucho entrenamiento.
Este resurgir de la IA ha sido, básicamente, consecuencia de la acumulación de cientos de miles de millones de datos proporcionados por los usuarios de internet, unos conscientemente y otros inconscientemente en pago por el uso de alguna red social o alguna herramienta «gratuita». De hecho, la disponibilidad de estos conjuntos de entrenamiento tan inmensamente grande es lo único que ha permitido la ilusión de disponer de un asistente inteligente de verdad y, repito, es una ilusión. Nunca te fíes de quien no puede explicarte porqué ha hecho o dicho algo… Y las IAs generativas no pueden.
¿Hay que descartar entonces el uso de estas IAs? No, en ningún caso, disponer de una herramienta entrenada con datos que nos son útiles (como todos los códigos de github que su copilot ha usado en su entrenamiento) nos pueden ahorrar mucho tiempo en disponer de versiones preliminares o códigos sin refinar. Pero siempre necesitaremos alguien para refinar los resultados de cualquier IA generativa. Simplemente porque la IA no sabe realmente qué es lo que está diciendo (y nunca lo sabrá). El hecho de que haya gente planeándose reemplazar personas humanas por IAs (o incluyo que ya lo han hecho) demuestra que hay trabajos de bajo valor añadido que no necesitan siquiera razonar correctamente para ser desempeñados, esos trabajos si que pueden ser reemplazados, pero igual es que la necesidad de éstos ya era algo anecdótico.
Hacer un servicio que sirva un API en python es muy, muy sencillo usando flask o connexion. Mi método favorito de hoy (esto cambia día a día) es usar connexion que nos permite crear un servidor teniendo su definición en un archivo openapi con simplemente tres líneas de código:
Con estas cuatro líneas de código (además de los imports correspondientes) ya tendríamos un servidor web en el puerto 8080 de la máquina. Luego basta con tener en el openapi.yml definido el nombre de las operationId e implementarlas adecuadamente… Me tienta, pero en este momento no voy a hacer un tutorial sobre connexion o sobre cómo generar un proyecto python usable. Para esta entrada supongamos que ya tenemos el servidor implementado y corriendo… Veremos que cuando lo arrancamos nos muestra este mensaje:
* Serving Flask app 'app'
* Debug mode: off
2024-01-25 20:57:13,203 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8080
* Running on http://172.18.0.20:8080
2024-01-25 20:57:13,204 - werkzeug - INFO - Press CTRL+C to quit
Si nos fijamos nos está advirtiendo de que el servidor que está usando es el propio de Flask y no es muy adecuado para entornos de producción. ¿Qué significa esto? Que si recibe muchas peticiones el tiempo de proceso de las mismas va a ser muy alto. El mismo mensaje nos recomienda usar un servidor WSGI para entornos de producción.
De hecho, si estás ejecutando una versión más moderna de connexion te aparecerá este mensaje en su lugar:
2024-01-25 22:05:31,351 - connexion.middleware.main - WARNING - `ConnexionMiddleware.run` is optimized for development. For production, run using a dedicated ASGI server.
Que es lo mismo pero con ASGI en lugar de WSGI. La receta para ejecutarlo mas en «producción» en este caso sería instalar gunicorn y lanzarlo con un tipo de worker ASGI (uvicorn en este caso) teniendo en cuenta que app está definido dentro del archivo app.py:.
Con esto ya se lanza 4 procesos para dar servicio al API… Esto debería mejorarlo.
Y una cosa más… Si tenéis algún proceso en la aplicación que no deba replicarse con cada worker (un scheduler por ejemplo), tenéis que lanzar gunicorn con el parámetro --preload para que se ejecute solo una instancia de la aplicación (de todo lo que no dependa de las peticiones)
Enviar correo desde una máquina virtual en Amazon siempre ha sido un castigo. Las limitaciones al puerto 25 y a los controles de tráfico de Amazon hacían poco recomendable poner un servidor de correo «normal» en la infraestructura. Sin embargo – y pagando, claro está – Amazon ha puesto a disposición de todo el mundo un servicio para poder enviar correos sin demasiada complicación (aunque, como veremos, también tiene sus limitaciones).
Lo primero es lo primero, si quieres mandar correos usando Amazon SES. La información general la puedes ver aquí: https://aws.amazon.com/es/ses/ y create una identidad verificada (tendrás que cambiar cosas en el dns para que puedas enviar correo desde cuentas de tu dominio. Lo siguiente será crear una configuración de SMTP para tu cuenta, eso te dará un servidor, usuario y contraseña que usar para mandar correos (y los puertos correspondientes)… Anotalos muy bien que será lo que vamos a utilizar.
Al principio tendrás unas limitaciones muy importantes (para probar no nos afectan demasiado) y tendrás que crear direcciones de correo validada, hazlo y prueba que puedes enviar correos a esas cuentas antes de continuar. Los pasos para poder enviar correo desde un servidor ubuntu serían los siguientes:
Y ya estaría, ya puedes enviar correos desde cuentas de tu dominio con sendmail. Si ves algún problema siempre puedes consultar el log en /var/log/mail.log
Si todo va bien lo siguiente es pedir a Amazon que, por favor, os pongan en producción el sistema para poder enviar correos a todo el mundo. Y ya si eso, en otro post, os cuento como configurar una imagen docker para que lo use…
Gestionar el consentimiento de las cookies
Si, es un coñazo, pero tengo que ponerte este aviso sobre las cookies y mi
Funcional
Siempre activo
El almacenamiento o acceso técnico es estrictamente necesario para el propósito legítimo de permitir el uso de un servicio específico explícitamente solicitado por el abonado o usuario, o con el único propósito de llevar a cabo la transmisión de una comunicación a través de una red de comunicaciones electrónicas.
Preferencias
El almacenamiento o acceso técnico es necesario para la finalidad legítima de almacenar preferencias no solicitadas por el abonado o usuario.
Estadísticas
El almacenamiento o acceso técnico que es utilizado exclusivamente con fines estadísticos.El almacenamiento o acceso técnico que se utiliza exclusivamente con fines estadísticos anónimos. Sin un requerimiento, el cumplimiento voluntario por parte de tu Proveedor de servicios de Internet, o los registros adicionales de un tercero, la información almacenada o recuperada sólo para este propósito no se puede utilizar para identificarte.
Marketing
El almacenamiento o acceso técnico es necesario para crear perfiles de usuario para enviar publicidad, o para rastrear al usuario en una web o en varias web con fines de marketing similares.