Created
November 12, 2025 06:09
-
-
Save Pastor/72a8992e5b0a6e025a468898a5723f2e to your computer and use it in GitHub Desktop.
M5 Capsule BLE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <M5Unified.h> | |
| #include <M5Capsule.h> | |
| #include <BLEDevice.h> | |
| #include <BLEUtils.h> | |
| #include <BLEScan.h> | |
| #include <BLEAdvertisedDevice.h> | |
| #include <FastLED.h> | |
| #include "EEPROM.h" | |
| #include "FS.h" | |
| #include "SD.h" | |
| #include "SPI.h" | |
| #define PIN_LED 21 | |
| #define NUM_LEDS 1 | |
| CRGB leds[NUM_LEDS]; | |
| BLEScan* scan; | |
| bool has_sd = false; | |
| enum ScanState { | |
| STATE_DISABLED, | |
| STATE_ENABLED, | |
| STATE_MIDDLE, | |
| STATE_FAILED | |
| }; | |
| ScanState state = STATE_MIDDLE; | |
| class SimpleBLEAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { | |
| void onResult(BLEAdvertisedDevice device) { | |
| File fd = SD.open("/ble/scan.csv", FILE_APPEND); | |
| if (!fd) { | |
| state = STATE_FAILED; | |
| return; | |
| } | |
| String address = device.getAddress().toString(); | |
| fd.printf("%d,%s", millis(), address.c_str()); | |
| fd.print(","); | |
| if (device.haveRSSI()) { | |
| fd.printf("%d", device.getRSSI()); | |
| } | |
| fd.print(","); | |
| if (device.haveName()) { | |
| fd.printf("%s", device.getName().c_str()); | |
| } | |
| fd.print(","); | |
| if (device.haveTXPower()) { | |
| fd.printf("%d", device.getTXPower()); | |
| } | |
| fd.print(","); | |
| if (device.haveServiceData()) { | |
| String serviceData = device.getServiceData(); | |
| uint8_t cServiceData[255]; | |
| size_t dataLength = serviceData.length(); | |
| if (dataLength <= sizeof(cServiceData)) { | |
| memcpy(cServiceData, serviceData.c_str(), dataLength); | |
| for (int i = 0; i < dataLength; i++) { | |
| fd.printf("%02X", cServiceData[i]); | |
| } | |
| } | |
| } | |
| fd.print(","); | |
| if (device.haveManufacturerData()) { | |
| String strManufacturerData = device.getManufacturerData(); | |
| uint8_t cManufacturerData[255]; | |
| size_t dataLength = strManufacturerData.length(); | |
| if (dataLength <= sizeof(cManufacturerData)) { | |
| memcpy(cManufacturerData, strManufacturerData.c_str(), dataLength); | |
| for (int i = 0; i < dataLength; i++) { | |
| fd.printf("%02X", cManufacturerData[i]); | |
| } | |
| } | |
| } | |
| fd.print(","); | |
| if (device.haveServiceUUID()) { | |
| BLEUUID uuid = device.getServiceUUID(); | |
| if (uuid.bitSize() > 0) { | |
| fd.printf("%s", uuid.toString().c_str()); | |
| } else { | |
| fd.print("00000000-00000000-00000000-00000000"); | |
| } | |
| } | |
| fd.printf(",%d", M5Capsule.Power.getBatteryLevel()); | |
| fd.println(); | |
| fd.close(); | |
| } | |
| }; | |
| void setLedState(ScanState state) { | |
| switch (state) { | |
| case STATE_DISABLED: | |
| leds[0] = CRGB::Red; | |
| break; | |
| case STATE_ENABLED: | |
| leds[0] = CRGB::Blue; | |
| break; | |
| case STATE_MIDDLE: | |
| leds[0] = CRGB::Green; | |
| break; | |
| case STATE_FAILED: | |
| leds[0] = CRGB::Yellow; | |
| break; | |
| } | |
| FastLED.show(); | |
| } | |
| void setup() { | |
| Serial.begin(115200); | |
| auto cfg = M5.config(); | |
| M5Capsule.begin(cfg); | |
| FastLED.addLeds<WS2812, PIN_LED, GRB>(leds, NUM_LEDS); | |
| setLedState(state); | |
| has_sd = SD.begin(); | |
| if (has_sd) { | |
| if (!SD.exists("/ble/scan.csv")) { | |
| SD.mkdir("/ble"); | |
| File fd = SD.open("/ble/scan.csv", FILE_WRITE); | |
| if (fd) { | |
| fd.println("mills,address,rssi,name,tx,service_data,manufacture_data,service_uuid,battery"); | |
| fd.close(); | |
| } | |
| } | |
| } | |
| BLEDevice::init(""); | |
| scan = BLEDevice::getScan(); | |
| scan->setAdvertisedDeviceCallbacks(new SimpleBLEAdvertisedDeviceCallbacks()); | |
| scan->setActiveScan(true); | |
| scan->setInterval(100); | |
| scan->setWindow(99); | |
| delay(1000); | |
| state = STATE_DISABLED; | |
| setLedState(state); | |
| M5.Speaker.begin(); | |
| M5.Speaker.stop(); | |
| } | |
| void loop() { | |
| M5Capsule.update(); | |
| if (M5Capsule.BtnA.wasClicked()) { | |
| if (state == STATE_DISABLED) { | |
| state = STATE_ENABLED; | |
| } else if (state == STATE_ENABLED || state == STATE_FAILED) { | |
| state = STATE_DISABLED; | |
| scan->clearResults(); | |
| //M5Capsule.Power.powerOff(); | |
| } | |
| setLedState(state); | |
| } | |
| if (state == STATE_ENABLED) { | |
| setLedState(STATE_ENABLED); | |
| BLEScanResults* foundDevices = scan->start(5, false); | |
| scan->clearResults(); | |
| setLedState(STATE_MIDDLE); | |
| delay(1000); | |
| if (M5Capsule.Power.getBatteryLevel() < 20) { | |
| M5.Speaker.tone(1000, 100); | |
| delay(1000); | |
| M5.Speaker.stop(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment