sinricpro / feature-requests

Feature request tracker for Sinric Pro
0 stars 0 forks source link

count bluetooth devices #44

Open EduAndrade87 opened 9 months ago

EduAndrade87 commented 9 months ago

I want to create with esp32 wrover. a code that counts nearby Bluetooth devices and sends the count to Alexa

example: Alexa, what is the Bluetooth device count?

Example output:

Alexa: Bluetooth device count is 3.

kakopappa commented 9 months ago

Hi @EduAndrade87

This can be achieved by creating a custom device type (device template)

  1. Go to Device Templates and create a new template

image

  1. Drang and drop a Range image

  2. Click Configure image

  3. Click Save

  4. Create a new device, select "Counter" as type

image

  1. Save the device and use "Generate Code" to generate the code for the custom device type.

image

Download the code, and update the secrets. Use the sendEvent to update the count value on the server.

Then, Alexa, what is the [range name] of [device name]

EduAndrade87 commented 9 months ago

When I put the library on Bluetooth the device does not connect to SinricPRO Can I use the Bluetooth library?

#include <WiFi.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <SinricPro.h>
#include "Contador.h"

#define APP_KEY    "*******************************"
#define APP_SECRET "*****************************"
#define DEVICE_ID  "********************************"
#define SSID       "LIVE TIM_RFC9_2G"
#define PASS       "**********************"

#define BAUD_RATE  115200

Contador &contador = SinricPro[DEVICE_ID];

BLEScan* pBLEScan; // Declarar um ponteiro para a varredura BLE
int scanTime = 5; // Tempo de varredura BLE em segundos

// RangeController
std::map<String, int> globalRangeValues;

// RangeController
bool onRangeValue(const String &deviceId, const String& instance, int &rangeValue) {
   Serial.printf("[Device: %s]: Value for \"%s\" changed to %d\r\n", deviceId.c_str(), instance.c_str(), rangeValue);
   globalRangeValues[instance] = rangeValue;
   return true;
}

bool onAdjustRangeValue(const String &deviceId, const String& instance, int &valueDelta) {
   globalRangeValues[instance] += valueDelta;
   Serial.printf("[Device: %s]: Value for \"%s\" changed about %d to %d\r\n", deviceId.c_str(), instance.c_str(), valueDelta, globalRangeValues[instance]);
   globalRangeValues[instance] = valueDelta;
   return true;
}

// RangeController
void updateRangeValue(String instance, int value) {
   contador.sendRangeValueEvent(instance, value);
}

void setupSinricPro() {

  // RangeController
   contador.onRangeValue("projeto", onRangeValue);
   contador.onAdjustRangeValue("projeto", onAdjustRangeValue);

   SinricPro.onConnected([]{ Serial.printf("[SinricPro]: Connected\r\n"); });
   SinricPro.onDisconnected([]{ Serial.printf("[SinricPro]: Disconnected\r\n"); });
   SinricPro.begin(APP_KEY, APP_SECRET);
};

void setupWiFi() {
   WiFi.begin(SSID, PASS);
   Serial.printf("[WiFi]: Connectando a: %s", SSID);
     while (WiFi.status() != WL_CONNECTED) {
     delay(500);
     Serial.print(".");
  }

   Serial.println("");
   Serial.println("Conectado à rede Wi-Fi");
   Serial.println(SSID);
   Serial.println("Endereço IP: " + WiFi.localIP().toString());
}

void setup() {
   Serial.begin(BAUD_RATE);
   Serial.println("Contagem de dispositivos Bluetooth iniciada...");
    // Inicializar a conexão Wi-Fi
   setupWiFi();

  // Configurar a biblioteca SinricPro
   setupSinricPro();

   BLEDevice::init("");
   pBLEScan = BLEDevice::getScan(); // Inicializar a varredura BLE
   pBLEScan->setActiveScan(true);
   pBLEScan->start(1000, false); // Iniciar a varredura por 1s
   delay(1000); // Aguardar a varredura ser concluída
}

int Dispositivos = 0; // Variável para armazenar o número de dispositivos detectados
void loop() {
   SinricPro.handle();

  // Iniciar a varredura BLE por um período de tempo e obter os resultados
   BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
   Serial.print("Número de dispositivos Bluetooth na sala: ");
   int Dispositivos = foundDevices.getCount();
   Serial.println(Dispositivos);
   updateRangeValue("projeto", Dispositivos);

}

image

kakopappa commented 9 months ago
void loop() {
SinricPro.handle();

// Iniciar a varredura BLE por um período de tempo e obter os resultados
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Número de dispositivos Bluetooth na sala: ");
int Dispositivos = foundDevices.getCount();
Serial.println(Dispositivos);
updateRangeValue("projeto", Dispositivos);
}
  1. Could be related to ESP not having enough memory or doing too much work in the main thread which blocks everything. Check troubleshooting tips at https://help.sinric.pro/pages/troubleshooting on how to enable SDK and ESP logs to get more details.

  2. 
    void loop() {
    SinricPro.handle();

.... updateRangeValue("projeto", Dispositivos); }



The above code may send too many events in a short period of time. Depending on the interval the server may throttle the connection and block any messages from processing. 

1. Check the count against the previously sent value (``Dispositivos``)
2. Send the count once every minute or so.

3. You have a bottleneck. antenna is being shared between WiFi and BLE. You may need to slow down on the scanning to keep the WiFi connection alive
EduAndrade87 commented 9 months ago

I made some changes to the code with your @kakopappa. I'm having trouble getting a response from Alexa. When I ask Alexa the question her answer is "I'm not sure". When I just say the name of the device "projeto" it also doesn't recognize the device Do I have to communicate in English or can I also communicate in Portuguese (BR)?

#include <WiFi.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <SinricPro.h>
#include "Contador.h"

#define APP_KEY    "*******************"
#define APP_SECRET "****************************"
#define DEVICE_ID  "********************************"
#define SSID       "********************"
#define PASS       "****************"

#define BAUD_RATE  115200

Contador &contador = SinricPro[DEVICE_ID];

BLEScan* pBLEScan; // Declarar um ponteiro para a varredura BLE
int scanTime = 5; // Tempo de varredura BLE em segundos

bool wifiConnected = false;

// RangeController
std::map<String, int> globalRangeValues;

// Classe de retorno de chamada para dispositivos BLE detectados
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.printf("Dispositivo encontrado: %s\n", advertisedDevice.toString().c_str());
  }
};

// RangeController
bool onRangeValue(const String &deviceId, const String& instance, int &rangeValue) {
  Serial.printf("[Device: %s]: Value for \"%s\" changed to %d\r\n", deviceId.c_str(), instance.c_str(), rangeValue);
  globalRangeValues[instance] = rangeValue;
  return true;
}

bool onAdjustRangeValue(const String &deviceId, const String& instance, int &valueDelta) {
  globalRangeValues[instance] += valueDelta;
  Serial.printf("[Device: %s]: Value for \"%s\" changed about %d to %d\r\n", deviceId.c_str(), instance.c_str(), valueDelta, globalRangeValues[instance]);
  globalRangeValues[instance] = valueDelta;
  return true;
}

void updateRangeValue(const String& instance, int value) {
  contador.sendRangeValueEvent(instance, value);
}

void setupSinricPro() {
  // RangeController
  contador.onRangeValue("projeto", onRangeValue);
  contador.onAdjustRangeValue("projeto", onAdjustRangeValue);

  SinricPro.onConnected([]{ 
    Serial.printf("[SinricPro]: Connected\r\n"); 
    wifiConnected = true; // Indica que a conexão WiFi está estabelecida
  });

  SinricPro.onDisconnected([]{ 
    Serial.printf("[SinricPro]: Disconnected\r\n"); 
    wifiConnected = false; // Indica que a conexão WiFi foi perdida
  });

  SinricPro.begin(APP_KEY, APP_SECRET);
}

void setupWiFi() {
  WiFi.begin(SSID, PASS);
  Serial.printf("[WiFi]: Conectando a: %s", SSID);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Conectado à rede Wi-Fi");
  Serial.println(SSID);
  Serial.println("Endereço IP: " + WiFi.localIP().toString());
  wifiConnected = true; // Indica que a conexão WiFi está estabelecida
}

void setupBLE() {
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); // Active scan usa mais energia, mas obtém resultados mais rápido
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99); // Menor ou igual ao valor de setInterval
}

void setup() {
  Serial.begin(BAUD_RATE);
  Serial.println("Contagem de dispositivos Bluetooth iniciada...");

  // Inicializar a conexão Wi-Fi
  setupWiFi();

  // Configurar a biblioteca SinricPro
  setupSinricPro();

  setupBLE();
}

void loop() {
  SinricPro.handle();

  // Iniciar a varredura BLE apenas se a conexão WiFi estiver estabelecida
  if (wifiConnected) {
    // Iniciar a varredura BLE por um período de tempo e obter os resultados
    BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
    Serial.print("Número de dispositivos Bluetooth na sala: ");
    Serial.println(foundDevices.getCount());

    delay(5000); // Aguarde antes de realizar a próxima varredura
    Serial.println("numero enviado");
    // Enviar o número de dispositivos detectados para SinricPro
    updateRangeValue("projeto", foundDevices.getCount());
  }

}
sivar2311 commented 9 months ago

What an interesting project!

I made it work: SinricPro BLE DeviceCounter

The NimBLE-Arduino Library is used because it requires little RAM and Flash.

The Sketch performs the BLE scan in continuous mode.

Each time a device is scanned, the address of the device is pushed to a std::map with the address as key and the current timestamp (millis) as value. This avoids multiple entries for the same addresses. The timestamp is used to delete devices from the list that have not been heard for a long period of time. This time is defined in the constant removeThresholdInMs.

A report is sent to SinricPro every minute if the number of devices has changed since the last report.

You can use the BLEDeviceCounter.json to import the custom device template.

Result: image

EduAndrade87 commented 9 months ago

@sivar2311 Thanks for the help with your code, it's more complete than mine. In my code I am not able to interact with Alexa. I ask but she can't give the answer to the number of devices that is showing on the sirinpro panel

image

sivar2311 commented 9 months ago

Hi @EduAndrade87 !

I have only implemented the sketch and written it so that BLE and SinricPro work together. I have not tested the voice commands - that is always a bit tricky. Check that you have set the correct locale: image