From b43782cf9f71d8219f7d495c0414802cfffb1b81963f83cd56c78d75e6a1a849 Mon Sep 17 00:00:00 2001 From: Sebastian Mariano Flores Date: Fri, 8 May 2026 10:55:59 -0600 Subject: [PATCH] Initial commit --- .gitignore | 2 + .vscode/extensions.json | 10 + .vscode/launch.json | 44 ++++ include/README | 37 ++++ lib/README | 46 ++++ platformio.ini | 15 ++ src/Python/ESP32_BLE.ipynb | 433 +++++++++++++++++++++++++++++++++++++ src/main.cpp | 79 +++++++ test/README | 11 + 9 files changed, 677 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 include/README create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/Python/ESP32_BLE.ipynb create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore index 0dad13a..ff5caf7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ # Built Visual Studio Code Extensions *.vsix +.pio +.venv \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..af93a3f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c2e55b3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,44 @@ +// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY +// +// PlatformIO Debugging Solution +// +// Documentation: https://docs.platformio.org/en/latest/plus/debugging.html +// Configuration: https://docs.platformio.org/en/latest/projectconf/sections/env/options/debug/index.html + +{ + "version": "0.2.0", + "configurations": [ + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug", + "executable": "/home/semarnat/Gitea/Programacion-II/BLUE_ESP32/.pio/build/esp32-s3-devkitc-1/firmware.elf", + "projectEnvName": "esp32-s3-devkitc-1", + "toolchainBinDir": "/home/semarnat/.platformio/packages/toolchain-xtensa-esp32s3/bin", + "internalConsoleOptions": "openOnSessionStart", + "preLaunchTask": { + "type": "PlatformIO", + "task": "Pre-Debug" + } + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (skip Pre-Debug)", + "executable": "/home/semarnat/Gitea/Programacion-II/BLUE_ESP32/.pio/build/esp32-s3-devkitc-1/firmware.elf", + "projectEnvName": "esp32-s3-devkitc-1", + "toolchainBinDir": "/home/semarnat/.platformio/packages/toolchain-xtensa-esp32s3/bin", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (without uploading)", + "executable": "/home/semarnat/Gitea/Programacion-II/BLUE_ESP32/.pio/build/esp32-s3-devkitc-1/firmware.elf", + "projectEnvName": "esp32-s3-devkitc-1", + "toolchainBinDir": "/home/semarnat/.platformio/packages/toolchain-xtensa-esp32s3/bin", + "internalConsoleOptions": "openOnSessionStart", + "loadMode": "manual" + } + ] +} diff --git a/include/README b/include/README new file mode 100644 index 0000000..b9e6a9a --- /dev/null +++ b/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..07b8d86 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..3142790 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,15 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32-s3-devkitc-1] +platform = espressif32 +board = esp32-s3-devkitc-1 +framework = arduino +monitor_speed = 115200 diff --git a/src/Python/ESP32_BLE.ipynb b/src/Python/ESP32_BLE.ipynb new file mode 100644 index 0000000..3eb4864 --- /dev/null +++ b/src/Python/ESP32_BLE.ipynb @@ -0,0 +1,433 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9e956603", + "metadata": {}, + "source": [ + "Explicación del código ESP32:\n", + "\n", + "\n", + "UUIDs: Son identificadores únicos. El SERVICE_UUID agrupa funciones, y el CHARACTERISTIC_UUID es el \"punto de datos\" específico.\n", + "\n", + "\n", + "\n", + "Advertising: Es la fase donde el ESP32 grita: \"¡Aquí estoy, soy un termómetro/sensor!\". Sin esto, la PC no lo vería.\n", + "\n", + "\n", + "\n", + "Properties: Definimos READ para que la PC pida el dato y NOTIFY para que el ESP32 envíe el dato automáticamente cuando cambie." + ] + }, + { + "cell_type": "markdown", + "id": "a3033892", + "metadata": {}, + "source": [ + "pip install bleak" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "7e11971c", + "metadata": {}, + "source": [ + "BleakScanner: Busca en el aire todas las señales Bluetooth cercanas. Usamos un filtro por nombre (DEVICE_NAME) para no conectar con el reloj inteligente del vecino.\n", + "\n", + "BleakClient: Establece la conexión segura con el dispositivo encontrado.\n", + "\n", + "read_gatt_char: Es la función clave. Accede al \"buzón\" (característica) del ESP32 y descarga los bytes almacenados.\n", + "\n", + "Async/Await: BLE es una operación asíncrona por naturaleza (hay tiempos de espera mientras se negocia la conexión), por lo que Python requiere asyncio para no bloquear el sistema.\n", + "\n", + "Diferencias Clave: BLE vs. Bluetooth Clásico\n", + "Es vital recordar que en BLE no se suelen usar \"puertos COM virtuales\" como en el Bluetooth de antes. En su lugar, el sistema funciona como una base de datos jerárquica (Perfil > Servicio > Característica).\n", + "\n", + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "markdown", + "id": "d258aa77", + "metadata": {}, + "source": [ + "Si el ESP32 no aparece en el escaneo de la PC, asegúrate de que no esté conectado a tu teléfono móvil al mismo tiempo, ya que BLE usualmente permite una sola conexión activa en modo periférico." + ] + }, + { + "cell_type": "markdown", + "id": "f4145f93", + "metadata": {}, + "source": [ + "Descubrir la MAC del BLE" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3c985611", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Nombre: Debian BLE Server | Dirección: E8:F6:0A:89:D6:8D\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Contador recibido: 23\n", + "Contador recibido: 24\n", + "Contador recibido: 25\n", + "Contador recibido: 26\n", + "Contador recibido: 27\n", + "Contador recibido: 28\n", + "Contador recibido: 29\n", + "Contador recibido: 30\n", + "Contador recibido: 31\n", + "Contador recibido: 32\n", + "Contador recibido: 33\n", + "Contador recibido: 34\n", + "Contador recibido: 35\n", + "Contador recibido: 36\n", + "Contador recibido: 37\n", + "Contador recibido: 38\n", + "Contador recibido: 39\n", + "Contador recibido: 40\n", + "Contador recibido: 41\n", + "Contador recibido: 42\n", + "Contador recibido: 43\n", + "Contador recibido: 44\n", + "Contador recibido: 45\n", + "Contador recibido: 46\n", + "Contador recibido: 47\n", + "Contador recibido: 48\n", + "Contador recibido: 49\n", + "Contador recibido: 50\n", + "Contador recibido: 51\n", + "Contador recibido: 52\n", + "Contador recibido: 53\n", + "Contador recibido: 54\n", + "Contador recibido: 55\n" + ] + } + ], + "source": [ + "import asyncio\n", + "import nest_asyncio\n", + "nest_asyncio.apply()\n", + "# Después de esto, tu código original con asyncio.run() debería funcionar\n", + "from bleak import BleakScanner\n", + "\n", + "async def run():\n", + " devices = await BleakScanner.discover()\n", + " for d in devices:\n", + " if d.name and \"Debian\" in d.name:\n", + " print(f\"Nombre: {d.name} | Dirección: {d.address}\")\n", + "\n", + "asyncio.run(run())" + ] + }, + { + "cell_type": "markdown", + "id": "35b7414a", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5ff5a9fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Conectado: True\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 21\u001b[39m\n\u001b[32m 17\u001b[39m \u001b[38;5;66;03m# Mantener el script vivo por 120 segundos\u001b[39;00m\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio.sleep(\u001b[32m120.0\u001b[39m)\n\u001b[32m 19\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m client.stop_notify(CHARACTERISTIC_UUID)\n\u001b[32m 20\u001b[39m \n\u001b[32m---> \u001b[39m\u001b[32m21\u001b[39m asyncio.run(main(ADDRESS))\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Gitea/Programacion-II/BLUE_ESP32/.venv/lib/python3.13/site-packages/nest_asyncio.py:30\u001b[39m, in \u001b[36m_patch_asyncio..run\u001b[39m\u001b[34m(main, debug)\u001b[39m\n\u001b[32m 28\u001b[39m task = asyncio.ensure_future(main)\n\u001b[32m 29\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m---> \u001b[39m\u001b[32m30\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[30;43mloop\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mrun_until_complete\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mtask\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 31\u001b[39m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[32m 32\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m task.done():\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Gitea/Programacion-II/BLUE_ESP32/.venv/lib/python3.13/site-packages/nest_asyncio.py:92\u001b[39m, in \u001b[36m_patch_loop..run_until_complete\u001b[39m\u001b[34m(self, future)\u001b[39m\n\u001b[32m 90\u001b[39m f._log_destroy_pending = \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[32m 91\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m f.done():\n\u001b[32m---> \u001b[39m\u001b[32m92\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_run_once\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 93\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._stopping:\n\u001b[32m 94\u001b[39m \u001b[38;5;28;01mbreak\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Gitea/Programacion-II/BLUE_ESP32/.venv/lib/python3.13/site-packages/nest_asyncio.py:115\u001b[39m, in \u001b[36m_patch_loop.._run_once\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 108\u001b[39m heappop(scheduled)\n\u001b[32m 110\u001b[39m timeout = (\n\u001b[32m 111\u001b[39m \u001b[32m0\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m ready \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m._stopping\n\u001b[32m 112\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28mmin\u001b[39m(\u001b[38;5;28mmax\u001b[39m(\n\u001b[32m 113\u001b[39m scheduled[\u001b[32m0\u001b[39m]._when - \u001b[38;5;28mself\u001b[39m.time(), \u001b[32m0\u001b[39m), \u001b[32m86400\u001b[39m) \u001b[38;5;28;01mif\u001b[39;00m scheduled\n\u001b[32m 114\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[32m--> \u001b[39m\u001b[32m115\u001b[39m event_list = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_selector\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mselect\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mtimeout\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 116\u001b[39m \u001b[38;5;28mself\u001b[39m._process_events(event_list)\n\u001b[32m 118\u001b[39m end_time = \u001b[38;5;28mself\u001b[39m.time() + \u001b[38;5;28mself\u001b[39m._clock_resolution\n", + "\u001b[36mFile \u001b[39m\u001b[32m/usr/lib/python3.13/selectors.py:452\u001b[39m, in \u001b[36mEpollSelector.select\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m 450\u001b[39m ready = []\n\u001b[32m 451\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m452\u001b[39m fd_event_list = \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_selector\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mpoll\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mtimeout\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mmax_ev\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 453\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mInterruptedError\u001b[39;00m:\n\u001b[32m 454\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m ready\n", + "\u001b[31mKeyboardInterrupt\u001b[39m: " + ] + } + ], + "source": [ + "import asyncio\n", + "from bleak import BleakClient\n", + "\n", + "# Cambia esta dirección por la de tu ESP32 (la verás al escanear)\n", + "# En Windows es una dirección MAC, en macOS es un UUID de sistema\n", + "ADDRESS = \"E8:F6:0A:89:D6:8D\" \n", + "CHARACTERISTIC_UUID = \"26dc4777-a57b-4caa-8a55-2be55a5663c6\"\n", + "\n", + "def callback(sender, data):\n", + " print(f\"Contador recibido: {data.decode('utf-8')}\")\n", + "\n", + "async def main(address):\n", + " async with BleakClient(address) as client:\n", + " print(f\"Conectado: {client.is_connected}\")\n", + " # Empezar a escuchar notificaciones\n", + " await client.start_notify(CHARACTERISTIC_UUID, callback)\n", + " # Mantener el script vivo por 120 segundos\n", + " await asyncio.sleep(120.0)\n", + " await client.stop_notify(CHARACTERISTIC_UUID)\n", + "\n", + "asyncio.run(main(ADDRESS))" + ] + }, + { + "cell_type": "markdown", + "id": "17aee4e3", + "metadata": {}, + "source": [ + "Para graficar:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfd5f06f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Intentando conectar a 10:B4:1D:EB:33:35...\n", + "Conectado con éxito!\n", + "Recibido: 25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Fidel\\AppData\\Local\\Temp\\ipykernel_3988\\4101542245.py:58: UserWarning: frames=None which we can infer the length of, did not pass an explicit *save_count* and passed cache_frame_data=True. To avoid a possibly unbounded cache, frame data caching has been disabled. To suppress this warning either pass `cache_frame_data=False` or `save_count=MAX_FRAMES`.\n", + " ani = FuncAnimation(fig, update, interval=100)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2157932ca1c4483cba86b3c037ffd020", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPZtJREFUeJzt3QeUU9Xe/vHf0IsUQapUEWmiKKiA7Sq8YkFFseCLVwQUlaI0Fa6i8oqi6FXAXkGvoIgKXvWqcEHBQkcsSBcFpdlgEBzKkP969vqfrCQzAwPOnJlkfz9rBSYnJ8lOzknOk91OWiQSiRgAAAC8UaSgCwAAAIBwEQABAAA8QwAEAADwDAEQAADAMwRAAAAAzxAAAQAAPEMABAAA8AwBEAAAwDMEQAAAAM8QAAEAADxDAAQAAPAMARAAAMAzBEAAAADPEAABAAA8QwAEAADwDAEQAADAMwRAAAAAzxAAAQAAPEMABAAA8AwBEAAAwDMEQAAAAM8QAAEAADxDAAQAAPAMARAAAMAzBEAAAADPEAABAAA8QwAEAADwDAEQAADAMwRAAAAAzxAAAQAAPEMABAAA8AwBEAAAwDMEQAAAAM8QAAEAADxDAATy0N/+9jd3Af6qa6+91urVq1fQxUhZ48ePt7S0NPv+++9ztX7v3r3tf/7nf6ww+Pbbb61YsWL2zTffFHRRkMQIgCgwa9assRtuuMGOOuooK1WqlJUvX95OPfVUGzNmjP3555/5+uV5zz335PqLv7BSONABLLvLueeeG7fup59+auedd54deeSR7r2uU6eOXXjhhTZx4sS49WIfo0iRIlazZk0755xz7OOPP45b7/7777fWrVtblSpV3OM1bNjQ+vfvbz///HPcesuXL7fbbrvNWrRoYeXKlbMaNWrYBRdcYAsXLsz169y3b5+9/PLLdsopp1ilSpXc4xxzzDF2zTXX2Ny5c6Prbdiwwa6++mpr1KiRW6dixYp28skn20svvWSRSMQKg5y2V+Il8f1O5ZAb+7pLlizptu1dd91lGRkZVlisXbvWnn/+efvHP/4RXabvj8Ttpu8w7euPP/64ZWZmxj2Gfhgee+yx+30efS/tb7/YtGmTW69p06buc6T3CThUxQ75nsBf8N5779nll1/uvvB1INcX4+7du11QufXWW23p0qX27LPP5lsAHD58uPtCTvYaFh1sBg0alGW5gltg8uTJduWVV7p1b7nlFjv88MPdAW327Nn23HPP2f/+7//G3Ve1HNomCk1a78knn7Szzz7bbTOFSFm0aJF7vC5duriwtWzZMvdYWmfJkiVWtmxZt54Omi+88IJ17tzZ1aBs27bNnnnmGRceP/jgA2vfvv0BX+PNN99sTzzxhF188cXWtWtXV/OxYsUKe//9992PBz2W/PLLL/bjjz/aZZdd5gLunj17bPr06S5kaH2F1oL2r3/9K+66gq3KmLi8SZMm7v1U+E11+g7QfiLaP95++22799573Q/ECRMmWGGgH6X169e3s846K8ttV111lZ1//vnR8v/nP/+xfv362Q8//GAPPfTQIT3fU089ZYcddliW5fpRE7jxxhvd8+p9atCgwSE9DzwXAUL23XffRQ477LBI48aNIxs2bMhy+6pVqyKjR4/Ot+efPHmyqoMiH330UZ4/9plnnukueWHPnj2RXbt25Xh73bp1IxdccMEBH6dp06aRZs2aZftYmzdvjruu96VPnz5xy7766iu3/Jxzztnv87zxxhtuvVdffTW6bOHChZHt27fHrffLL79EqlSpEjn11FMPWPZNmzZF0tLSItdff32W2/bt25el/Nnp2LFjpGzZspG9e/dGChu91z5/DXfr1s1tm8Tt2rp1a7fdtf3zy7hx49x7v3bt2v2ut3v37sgRRxwRufPOO+OW6366/0MPPZSl/CeddFKkZs2accv1vaDP4f7cfffd7jF//vnnA5Zf5Tr88MMjw4YNO+C6QHZoAkboRo0aZX/88YerGVKTYKKjjz7a1VQF9u7d62oE9CtXtQWqtVNTzK5du+Lup+UdO3Z0tYhq+lPTpGqIVMsS2+9HNY+iX/OJTW6qfVDTimrQ9Fx6Tj13YnOOqIZSt5cuXdo93yeffJLt692yZYv17NnTqlWr5sp0/PHHu2bJWEFz0sMPP2yjR4+OvlbVVv5VqiE46aSTrESJElluq1q16gHv37x5czviiCNcbeD+BLWpW7dujS5r2bJllpqMypUr2+mnn+5qDQ9Ez6lcqq4BifR+5ab8KtfOnTtdDfOB/PTTT9ajRw+3rfT+N2vWzF588cW4dbSv6Llff/11u++++6xWrVpuu7Zr185Wr15t+dkHUDWC2j9ULj2nyqluFL///nu2nwWVtVWrVm4f1XYM9vO33nrLXddj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ti1btrhgd8MNN7iJnwO33Xab7dixw3r16mVbt2610047zT744AMrVapUgZYdAAAgP6XsPIBhYB4hAACSTzrH79TtAwgAAIDsEQABAAA8QwAEAADwDAEQAADAMwRAAAAAzxAAAQAAPEMABAAA8AwBEAAAwDMEQAAAAM8QAAEAADxDAAQAAPAMARAAAMAzBEAAAADPhBIA9+7day+//LJt3rw5jKcDAABAQQfAYsWK2Y033mgZGRlhPB0AAAAKQxPwySefbEuWLAnr6QAAAJCDYhaS3r1728CBA239+vXWsmVLK1u2bNztxx13XFhFAQAA8FpaJBKJhPFERYpkrWxMS0szPb3+z8zMtGSTnp5uFSpUsG3btln58uULujgAACAX0jl+h1cDuHbt2rCeCgAAAIUhANatWzespwIAAEBhCICyZs0aGz16tC1btsxdb9q0qd1yyy3WoEGDMIsBAADgtdBGAX/44Ycu8M2fP98N+NBl3rx51qxZM5s+fXpYxQAAAPBeaINATjjhBOvQoYM98MADccuHDBli06ZNs8WLF1uyoRMpAADJJ53jd3g1gGr27dmzZ5blPXr0sG+//TasYgAAAHgvtABYpUqVbCeC1rKqVauGVQwAAADvhTYI5Prrr7devXrZd999Z23btnXLPvvsM3vwwQfdBNEAAABIsT6AehqNAP7nP/9pGzZscMtq1qxpt956q918881uMuhkQx8CAACSTzrH7/ACYKzt27e7/8uVK2fJjB0IAIDkk87xO9x5AAPJHvwAAACSWbH8nvolt027yTgNDAAAQDLK1wDYqVOn6N8ZGRn25JNPusmg27Rp45bNnTvXli5dar17987PYgAAACCsAHj33XdH/77uuuvcYI977703yzrr16/Pz2IAAACgIAaBqLPlwoULrWHDhnHLV61aZa1atXIdMZMNnUgBAEg+6Ry/w5sIunTp0m7ev0RaVqpUqbCKAQAA4L3QRgH379/fbrrpJjfY4+STT3bL5s2bZy+++KINGzYsrGIAAAB4L7QAOGTIEDvqqKNszJgx9sorr7hlTZo0sXHjxtkVV1wRVjEAAAC8VyATQacK+hAAAJB80jl+h9cHEAAAAJ41AWdmZtqjjz5qr7/+uq1bt852794dd/tvv/0WVlEAAAC8FloN4PDhw+2RRx6xK6+80lW5Dhw40C699FIrUqSI3XPPPWEVAwAAwHuhBcAJEybYc889Z4MGDbJixYrZVVddZc8//7zddddd7owgAAAASLEAuGnTJmvevLn7+7DDDotO/NyxY0d77733wioGAACA90ILgLVq1bKNGze6vxs0aGDTpk1zfy9YsMBKliwZVjEAAAC8F1oAvOSSS2zGjBnu7379+rnJn3VauGuuucZ69OgRVjEAAAC8V2DzAKrf3+eff+5C4IUXXmjJiHmEAABIPukcv8ObBmb27NnWtm1bNwBEWrdu7S579+51t51xxhlhFQUAAMBroTUBn3XWWdnO9af0rdsAAACQYgFQLc1paWlZlv/6669WtmzZsIoBAADgvXxvAtZkz6Lwd+2118aN+NXZQb766ivXNAwAAIAUCYDqZBnUAJYrV85Kly4dva1EiRKuH+D111+f38UAAABAWAFw3Lhx7v969erZ4MGDae4FAADwdRqYVMAwcgAAkk86x+/wBoFs3rzZ/v73v1vNmjXdVDBFixaNuwAAACDF5gHUAJB169a5M4DUqFEj2xHBAAAASKEA+Omnn9onn3xiLVq0COspAQAAUJBNwLVr13YjgQEAAOBJABw9erQNGTLEvv/++7Ce0n766Se7+uqrrXLlym76mebNm9vChQujtyuQ3nXXXa5JWre3b9/eVq1aFVr5AAAAUroJ+Morr7SdO3dagwYNrEyZMla8ePG427M7Tdxf8fvvv9upp57qTjP3/vvvW5UqVVy4O/zww6PrjBo1ysaOHWsvvfSS1a9f3/VP7NChg3377bdWqlSpPC0PAACAdwFQNYBhevDBB12zczAPoSjkxdb+qUx33nmnXXzxxW7Zyy+/bNWqVbOpU6daly5dQi0vAABAWFJ2HsCmTZu62rwff/zRZs2aZUceeaT17t07etaR7777ztVGfvHFF3EDU84880x3fcyYMQd8DuYRAgAg+aRz/A6vBjA4969q15YtW+auN2vWzC666KJ8mQdQAe+pp56ygQMH2j/+8Q9bsGCB3Xzzze70c926dbNNmza59VTjF0vXg9sS7dq1y11idyAAAIBkE1oAXL16tZ1//vluYEajRo3cspEjR7pm2vfee8/VxuWlffv2WatWrez+++9310844QT75ptv7Omnn3YB8FCovMOHD8/TcgIAAKTsKGDVvinkrV+/3hYvXuwumhha/fJ0W17TyF41A8dq0qSJe06pXr169AwlsXQ9uC3R0KFDXXVxcNFrAQAASDah1QCqH97cuXOtUqVK0WWanuWBBx5wo3Xzmh5zxYoVcctWrlxpdevWdX8reCrozZgxI9oHUE268+bNs5tuuinbxyxZsqS7AAAAJLPQAqCC0/bt27Ms/+OPP1y/vLw2YMAAa9u2rWsCvuKKK2z+/Pn27LPPuovoVHT9+/e3ESNGWMOGDaPTwOhcxZ06dcrz8gAAAHjXBNyxY0fr1auXq2HTwGNdVCN44403uoEgee2kk06yKVOm2KuvvmrHHnus3XvvvW7al65du0bXue2226xfv36uXFpfYfSDDz5gDkAAAJDSQpsGZuvWrW7wxTvvvBOdBHrv3r0u/I0fP94Nx042DCMHACD5pHP8Dq8JuGLFivb222+70cDBNDAalHH00UeHVQQAAACEFQCVtA877DArUqSIC3xB6NNULbrN1/QNAACQkn0A1Q9P8/FlZGRkue3PP/90fe/ULAwAAIAUCYA6G4cGW5QpUybLbWXLlrXbb7/dHn/88fwuBgAAAMIKgDr7xt/+9rccbz/jjDPs66+/zu9iAAAAIKwA+Pvvv7vRvjnZs2ePWwcAAAApEgDr1atnCxcuzPF23RacnQMAAAApEAAvvfRSu+OOO7Kcc1c2bdpkd955p3Xu3Dm/iwEAAICwJoLW6d/atGlj69ats6uvvtoaNWrkli9fvtwmTJhgtWvXdmcEKVeunCUbJpIEACD5pHP8zv95ABXsPvvsMxs6dKhNmjQp2t9PE0MrEN53331JGf4AAACSVWinghM91S+//OL+r1KliqWlpVky4xcEAADJJ53jd3inghMFPgU/AAAApPAgEAAAABQuBEAAAADPEAABAAA8QwAEAADwTL4OAhk7dmyu17355pvzsygAAAAIYxqY+vXr53p08HfffWfJhmHkAAAkn3SO3/lbA7h27dr8fHgAAAAkQx/A3bt324oVK2zv3r1hPzUAAADCDIA7d+60nj17WpkyZaxZs2bu3MDSr18/e+CBB8IqBgAAgPdCC4A6F/CXX35pH3/8sZUqVSq6vH379u4cwQAAAEixU8FNnTrVBb3WrVvHnQNYtYFr1qwJqxgAAADeC60G8Oeff7aqVatmWb5jx464QAgAAIAUCYCtWrWy9957L3o9CH3PP/+8tWnTJqxiAAAAeC+0JuD777/fzjvvPPv222/dCOAxY8a4vz///HObNWtWWMUAAADwXmg1gKeddpotWbLEhb/mzZvbtGnTXJPwnDlzrGXLlmEVAwAAwHv5eiaQVMdM4gAAJJ90jt/52wSsNzi3fN0AAAAAKRUAK1asmOsRvpmZmflZFAAAAIQRAD/66KPo399//70NGTLErr322uioX/X/e+mll2zkyJH5WQwAAAAURB/Adu3a2XXXXWdXXXVV3PKJEyfas88+684QkmzoQwAAQPJJ5/gd3ihg1fZpLsBEWjZ//vywigEAAOC90AJg7dq17bnnnsuyXBNB6zYAAACk2ETQjz76qHXu3Nnef/99O+WUU9wy1fytWrXK3nzzzbCKAQAA4L3QagDPP/98F/Yuuugi++2339zlwgsvtJUrV7rbAAAAEA4mgv4L6EQKAEDySef4HV4NIAAAAAoHAiAAAIBnCIAAAACeCSUAqpvhunXrLCMjI4ynAwAAQGEIgEcffbStX78+jKcDAABAQQfAIkWKWMOGDe3XX38N4+kAAABQGPoAPvDAA3brrbfaN998E9ZTAgAAoCDnATz88MNt586dtnfvXitRooSVLl067nZNDJ1smEcIAIDkk87xO7xTwY0ePTqspwIAAEBhCIDdunUL66kAAABQGAKgZGZm2tSpU23ZsmXuerNmzdy5gYsWLRpmMQAAALwWWgBcvXq1nX/++fbTTz9Zo0aN3LKRI0da7dq17b333rMGDRqEVRQAAACvhTYK+Oabb3YhT3MBLl682F00OXT9+vXdbQAAAEixGsBZs2bZ3LlzrVKlStFllStXdtPDnHrqqWEVAwAAwHuh1QCWLFnStm/fnmX5H3/84aaFAQAAQIoFwI4dO1qvXr1s3rx57tRwuqhG8MYbb3QDQQAAAJBiAXDs2LGuD2CbNm2sVKlS7qKmX50jeMyYMWEVAwAAwHuh9QGsWLGivf3227Zq1Spbvny5W9akSRMXAAEAAJCi8wBKw4YN3QUAAAApGAAHDhyY63UfeeSRfCuHRhoPHTrUbrnllugp6TIyMmzQoEH22muv2a5du6xDhw725JNPWrVq1fKtHAAAACkfAL/44otcrZeWlpZvZViwYIE988wzdtxxx8UtHzBggJuAevLkye6E0H379rVLL73UPvvss3wrCwAAQMoHwI8++sgKkqaY6dq1qz333HM2YsSI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NGEt+VzQBHwoNAWMmlf0QT755JNt9OjRrsN19+7dC7poXnyA9estduCHvlQ18ECdd9UPbcSIEdawYUMXSIYNG+Y6AGuOOuR9s+/EiRPt7bffdnMBBv1mNPBGzSv6v2fPnu7zou2j+en69evnvlxbt25d0MVPKUOHDnXNXfoMbN++3W2Xjz/+2D788EO2Q8j0WQj6wQY0HZXmmguWsz3CMXjwYDdvrJp9NcWLpm5TC95VV13F50IKehhysnrsscciderUiZQoUcJNCzN37tyCLpIXPvroIzdMP/HSrVu36FQww4YNi1SrVs1N/9KuXbvIihUrCrrYKSm77aDLuHHjouv8+eefkd69e7spScqUKRO55JJLIhs3bizQcqeiHj16ROrWreu+j6pUqeL2+2nTpkVvZzsUrNhpYITtEY4rr7wyUqNGDfe5OPLII9311atXR2//0/PtkKZ/CjqEAgAAIDz0AQQAAPAMARAAAMAzBEAAAADPEAABAAA8QwAEAADwDAEQAADAMwRAAAAAzxAAAQAAPEMABFDoXXvttZaWlmY33nhjtqek021aJwzjx493J5UHgGRGAASQFGrXrm2vvfaa/fnnn9FlGRkZ7ry3OgduYbN79+6CLgIA5IgACCApnHjiiS4EvvXWW9Fl+lvh74QTToguq1evno0ePTruvi1atLB77rknen3r1q123XXXWZUqVdxJ4M8++2z78ssvo7fr77POOsvKlSvnbm/ZsqUtXLjQPv74Y+vevbtt27bN1TrqEjyunvfee++1a665xt2nV69ebvntt99uxxxzjJUpU8aOOuooGzZsmO3Zs+eAzwUA+YkACCBp9OjRw8aNGxe9/uKLL7pAdrAuv/xy27Jli73//vu2aNEiFy7btWtnv/32m7u9a9euVqtWLVuwYIG7fciQIVa8eHFr27atC5cKahs3bnSXwYMHRx/34YcftuOPP96++OILF/REwU7Nxt9++62NGTPGnnvuOXv00Uej98npuQAgPxXL10cHgDx09dVX29ChQ+2HH35w1z/77DPXLKyaudz69NNPbf78+S4AlixZMhrcpk6dam+88YaruVu3bp3deuut1rhxY3d7w4YNo/evUKGCq/mrXr16lsdWTeKgQYPilt15553Rv1VLqMCoMt92221u2f6eCwDyCwEQQNJQk+0FF1zgatQikYj7+4gjjjiox1CT6x9//GGVK1eOW66+hWvWrHF/Dxw40DUR/+tf/7L27du7GsMGDRoc8LFbtWqVZdmkSZNs7Nix7rH1vHv37nU1iIFDfS4A+CtoAgaQdM3ACoAvvfSS+ztRkSJFXDiMFdvnTiGsRo0atmTJkrjLihUrXE2cqF/f0qVLXcCcOXOmNW3a1KZMmXLAspUtWzbu+pw5c1wT7/nnn2/vvvuuaxq+44474gaIHOpzAcBfQQ0ggKRy7rnnugClZtgOHTpkW0uovnmB9PR0W7t2bfS6+vtt2rTJihUr5ppkc6KBG7oMGDDArrrqKtf38JJLLrESJUpYZmZmrsr6+eefW926dV3oCwTN17l5LgDIL9QAAkgqRYsWtWXLlrlBFfo7u354ak795JNP7Ouvv7Zu3brFradm1jZt2linTp1s2rRp9v3337ugppCm0bdqCu7bt6/rV6iwpn6GGqDRpEkTd3+FRtUizpgxw3755RfbuXNnjmVVfz718VOfPzUBqyk4tnbvQM8FAPmFAAgg6agPXWw/ulgaJHLmmWdax44dXbOqgl5snzrVHP7nP/+xM844w40gVs1bly5dXACrVq2aC4u//vqrm85Ft11xxRV23nnn2fDhw939NRJYE1JfeeWVrrZx1KhROZbzoosucrV6CnmaikZBMxgdLAd6LgDIL2mRxM4yAAAASGnUAAIAAHiGAAgAAOAZAiAAAIBnCIAAAACeIQACAAB4hgAIAADgGQIgAACAZwiAAAAAniEAAgAAeIYACAAA4BkCIAAAgGcIgAAAAOaX/wcKV6CWZinhQAAAAABJRU5ErkJggg==", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Recibido: 26\n", + "Recibido: 27\n", + "Recibido: 28\n", + "Recibido: 29\n", + "Recibido: 30\n", + "Recibido: 31\n", + "Recibido: 32\n", + "Recibido: 33\n", + "Recibido: 34\n", + "Recibido: 35\n", + "Recibido: 36\n", + "Recibido: 37\n", + "Recibido: 38\n", + "Recibido: 39\n", + "Recibido: 40\n", + "Recibido: 41\n", + "Recibido: 42\n", + "Recibido: 43\n", + "Recibido: 44\n", + "Recibido: 45\n", + "Recibido: 46\n", + "Recibido: 47\n", + "Programa finalizado.\n" + ] + } + ], + "source": [ + "import asyncio\n", + "import nest_asyncio\n", + "nest_asyncio.apply()\n", + "%matplotlib widget\n", + "import matplotlib.pyplot as plt\n", + "from bleak import BleakClient\n", + "from matplotlib.animation import FuncAnimation\n", + "\n", + "# Configuración - Usa la dirección que encontraste previamente\n", + "ADDRESS = \"10:B4:1D:EB:33:35\"\n", + "CHARACTERISTIC_UUID = \"beb5483e-36e1-4688-b7f5-ea07361b26a8\" \n", + "\n", + "# Datos para la gráfica\n", + "x_data = []\n", + "y_data = []\n", + "\n", + "def notification_handler(sender, data):\n", + " \"\"\"Maneja los datos recibidos por BLE.\"\"\"\n", + " valor_texto = data.decode('utf-8')\n", + " valor_int = int(valor_texto)\n", + " print(f\"Recibido: {valor_int}\")\n", + " \n", + " # Guardar datos para graficar\n", + " y_data.append(valor_int)\n", + " x_data.append(len(y_data))\n", + " \n", + " # Limitar la gráfica a los últimos 50 puntos para que sea legible\n", + " if len(x_data) > 50:\n", + " x_data.pop(0)\n", + " y_data.pop(0)\n", + "\n", + "async def run_ble(client):\n", + " \"\"\"Mantiene activa la suscripción a notificaciones.\"\"\"\n", + " await client.start_notify(CHARACTERISTIC_UUID, notification_handler) \n", + " while True:\n", + " await asyncio.sleep(1)\n", + "\n", + "async def main():\n", + " print(f\"Intentando conectar a {ADDRESS}...\")\n", + " async with BleakClient(ADDRESS) as client:\n", + " print(f\"Conectado con éxito!\")\n", + " \n", + " # Configuración de la gráfica\n", + " fig, ax = plt.subplots()\n", + " line, = ax.plot([], [], 'r-')\n", + " ax.set_ylim(0, 110)\n", + " ax.set_xlim(0, 50)\n", + " ax.set_title(\"Contador ESP32-S3 en Tiempo Real (BLE)\")\n", + " ax.set_xlabel(\"Muestras\")\n", + " ax.set_ylabel(\"Valor del Contador\")\n", + "\n", + " def update(frame):\n", + " line.set_data(range(len(y_data)), y_data)\n", + " ax.set_xlim(0, max(50, len(y_data)))\n", + " return line,\n", + "\n", + " # Animación de Matplotlib\n", + " ani = FuncAnimation(fig, update, interval=100)\n", + " \n", + " # Ejecutar BLE en segundo plano mientras se muestra la gráfica\n", + " await asyncio.gather(\n", + " run_ble(client),\n", + " asyncio.to_thread(plt.show)\n", + " )\n", + "\n", + "if __name__ == \"__main__\":\n", + " try:\n", + " asyncio.run(main())\n", + " except KeyboardInterrupt:\n", + " print(\"Programa finalizado.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54b556f4", + "metadata": {}, + "outputs": [], + "source": [ + "import asyncio\n", + "import nest_asyncio\n", + "from bleak import BleakClient\n", + "import matplotlib.pyplot as plt\n", + "\n", + "nest_asyncio.apply()\n", + "\n", + "# Configuración - Usa la dirección que encontraste previamente\n", + "ADDRESS = \"10:B4:1D:EB:33:35\"\n", + "CHARACTERISTIC_UUID = \"beb5483e-36e1-4688-b7f5-ea07361b26a8\" \n", + "\n", + "# Datos para la gráfica\n", + "x_data = []\n", + "y_data = []\n", + "\n", + "async def notification_handler(sender, data):\n", + " valor = int(data.decode('utf-8')) \n", + " y_data.append(valor)\n", + " if len(y_data) > 50: y_data.pop(0)\n", + "\n", + "async def main():\n", + " # Crear la figura fuera del loop\n", + " plt.ion() # Activar modo interactivo\n", + " fig, ax = plt.subplots()\n", + " line, = ax.plot([], [], 'r-')\n", + " ax.set_ylim(0, 110)\n", + " \n", + " async with BleakClient(ADDRESS) as client: \n", + " await client.start_notify(CHARACTERISTIC_UUID, notification_handler)\n", + " \n", + " while True:\n", + " if y_data:\n", + " line.set_xdata(range(len(y_data)))\n", + " line.set_ydata(y_data)\n", + " ax.set_xlim(0, max(50, len(y_data)))\n", + " fig.canvas.draw()\n", + " fig.canvas.flush_events()\n", + " \n", + " await asyncio.sleep(0.1) # Breve pausa para no saturar el procesador\n", + " \n", + "if __name__ == \"__main__\":\n", + " try:\n", + " asyncio.run(main())\n", + " except KeyboardInterrupt:\n", + " print(\"Programa finalizado.\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv (3.13.5)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..0af406c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,79 @@ +#include + +#include +#include +#include +#include + +BLEServer* pServer = NULL; +BLECharacteristic* pCharacteristic = NULL; +bool deviceConnected = false; +int contador = 0; + +// UUIDs únicos (puedes generar los tuyos en uuidgenerator.net) +#define SERVICE_UUID "794ff2e6-d4ac-4b80-b97e-dad2d577f17b" +#define CHARACTERISTIC_UUID "26dc4777-a57b-4caa-8a55-2be55a5663c6" + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + }; + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + // Reiniciar publicidad para permitir reconexión + pServer->getAdvertising()->start(); + } +}; + +void setup() { + Serial.begin(115200); + + // Inicializar dispositivo + BLEDevice::init("Debian BLE Server"); + + // Crear Servidor BLE + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Crear Servicio + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Crear Característica con Notificación + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_NOTIFY + ); + + // Descriptor necesario para notificaciones (Client Characteristic Configuration) + pCharacteristic->addDescriptor(new BLE2902()); + + pService->start(); + + // Iniciar Publicidad (Advertising) + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->start(); + Serial.print("Dirección del dispositivo: "); + Serial.println(BLEDevice::getAddress().toString().c_str()); + Serial.println("Esperando conexión BLE..."); +} + +void loop() { + if (deviceConnected) { + if (contador <= 100) { + char str[10]; + itoa(contador, str, 10); // Convertir int a string + + pCharacteristic->setValue(str); + pCharacteristic->notify(); // Enviar valor a la PC + + Serial.printf("Enviando: %d\n", contador); + contador++; + } else { + contador = 0; // Reiniciar si llega a 100 + } + delay(1000); // Enviar cada segundo + } +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..d1c31b8 --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html