How to send Bluetooth data from ESP32 in arduino? - arduino

Easy to handle received data with BLE but can't send data.
I'm using ESP32 BLE Uart code.
It's easy to get data from RxCharateristic but I don't know how to send data.
I'm trying to use TxCharacteristic to send data with BLE.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
Serial.print(rxValue[i]);
}
}
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("TheOneSystem");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify();
txValue++;
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
I can easily handle received data with this part of code
class MyCallbacks: public BLECharacteristicCallbacks {
String bleData;
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
//Serial.print(rxValue[i]);
bleData=bleData+rxValue[i];
}
Serial.println();
Serial.println(bleData);
Serial.println("*********");
int first = bleData.indexOf(",");
String bleSSID = bleData.substring(0, first);
String blepw = bleData.substring(first+1, bleData.length());
Serial.println("Wifi : " + bleSSID + "," + "Password : " + blepw);
bleData="";
}
}
};
How to send data by using TxCharacteristic?
In my receiving code, I'm using this function to use callback.
if(pTxCharacteristic->canNotify()) {
pTxCharacteristic->registerForNotify(notifyCallback);
}
And here is my notifyCallback function i got from Google.
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify){
Serial.println(data);
}
It seems like i have to add a little function in notifyCallback.
However errors continue to occur. I can't get data. Tnx for help.

Related

ESP32 Scan for BLE devices with in mesh network

I'm working on a project where I have 3 esp32s in a mesh network that each scans for a 4th to 5th esp32 that inst in the mesh network to get the RSSI of the BLE advertisement.
I made code where I'm doing these 2 parts separately but then I try to merge them it doesn't work.
Could it be that its not possible to scan for a BLE advertisement while in a Mesh network?
Updated with Source code:
#include "painlessMesh.h"
#define MESH_PREFIX "cowFarmMeshNetwork"
#define MESH_PASSWORD "cowFarmMeshNetwork"
#define MESH_PORT 5555
#define COW1_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d"
#define COW2_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4e"
#define DEVICE_NAME "Device2"
String cowRssi = "";
String CowUUID = "";
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
void sendMessage() {
String msg = "";
String testS= ",";
if(CowUUID == COW1_UUID){
String cow = "cow1";
msg = DEVICE_NAME + testS + cow + testS + cowRssi;
} else if(CowUUID == COW2_UUID){
String cow = "cow2";
msg = DEVICE_NAME + testS + cow + testS + cowRssi;
}
mesh.sendBroadcast( msg );
taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}
// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
Serial.printf("Changed connections\n");
}
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLEEddystoneURL.h>
#include <BLEEddystoneTLM.h>
#include <BLEBeacon.h>
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
int scanTime = 5; //In seconds
BLEScan *pBLEScan;
String strDistance = "";
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice)
{
if (advertisedDevice.haveManufacturerData() == true)
{
std::string strManufacturerData = advertisedDevice.getManufacturerData();
uint8_t cManufacturerData[100];
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
{
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData);
String beacon = oBeacon.getProximityUUID().toString().c_str();;
if( beacon == "8ec76ea3-6668-48da-9866-75be8bc86f4d" || beacon == "8ec76ea3-6668-48da-9866-75be8bc86f4e"){
Serial.println("inside");
CowUUID = beacon;
cowRssi = String(advertisedDevice.getRSSI());
}
}
}
return;
}
};
void setup() {
Serial.begin(115200);
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(60000);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void loop() {
// it will run the user scheduler as well
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
mesh.update();
}

Problem Reading From Thingspeak from Arduino

I am using this code to retrieve data from a Thingspeak channel in a JSON format. I am using an ESP8266 along with an Arduino Nano 33 BLE. The Nono 33 BLE Arduino board is not compatible with Thingspeak library and it doesn’t support SoftwareSerial. Alternatively, I am using serial1 to communicate with the ESP8266 and REST API method to get the data from Thingspeak as it is shown in the code. However, I cannot get it to work. It is worth noting that Serial1.available() always gives zero even after adding delays.
I have used the same code to send data to the same Thingspeak channel and it works perfectly. I have no clue why it is not reading from the channel. I would really appreciate any help with this problem
Thanks in advance.
String AP ="xxxxxxxxxxx";
String PASS ="xxxxxxxxxxxxxx";
String PORT = "80";
String field = "Id";
int countTrueCommand;
int countTimeCommand;
boolean found = false;
String Data ="";
void setup() {
Serial.begin(9600);
Serial1.begin(115200);
sendCommand("AT",5,"OK",false);
Serial1.println("AT+UART_DEF=9600,8,1,0,0");
delay(1000);
Serial1.end();
Serial1.begin(9600);
ConnectToWifi();
}
void loop() {
String getData="GET https://api.thingspeak.com/channels/1335558/fields/1?api_key=7XFZKXEGOV5HY4TQ";
sendCommand("AT+CIPMUX=1",5,"OK",false);
sendCommand("AT+CIPSTART=4,\"TCP\",\""+ HOST +"\","+ PORT,15,"OK",false);
sendCommand("AT+CIPSEND=4," +String(getData.length()+4),4,">",false);
sendCommand(getData,20,"OK",true);
delay(1500);
countTrueCommand++;
sendCommand("AT+CIPCLOSE=0",5,"OK",false);
}
bool ConnectToWifi(){
for (int a=0; a<15; a++)
{
sendCommand("AT",5,"OK",false);
sendCommand("AT+CWMODE=1",5,"OK",false);
boolean isConnected = sendCommand("AT+CWJAP=\""+ AP +"\",\""+ PASS +"\"",20,"OK",false);
if(isConnected)
{
return true;
}
}
}
bool sendCommand(String command, int maxTime, char readReplay[],boolean isGetData) {
boolean result=false;
//Test Purpose
Serial.print(countTrueCommand);
Serial.print(". at command => ");
Serial.print(command);
Serial.print(" ");
while(countTimeCommand < (maxTime*1))
{
Serial1.println(command);
if(Serial1.find(readReplay))//ok
{
if(isGetData)
{
if(Serial1.find(readReplay))
{
Serial.println("Success : Request is taken from the server");
}
while(Serial1.available())
{
char character = Serial1.read()
Data.concat(character); /
if (character == '\n')
{
Serial.print("Received: ");
Serial.println(Data);
delay(50);
Data = "";
}
}
}
result = true;
break;
}
countTimeCommand++;
}
if(result == true)
{
Serial.println("Success");
countTrueCommand++;
countTimeCommand = 0;
}
if(result == false)
{
Serial.println("Fail");
countTrueCommand = 0;
countTimeCommand = 0;
}
found = false;
return result;

How do I send multiple 32 byte strings to I2C master?

I have multiple variable length strings which do not exceed 32 bytes each which need to be sent via I2C between 2 Arduino Nanos. I use # to terminate each string. I can successfully send and receive the first string, but for the life of me I can't figure out how to send the succeeding strings. The samples I am testing with look like this:
String answer = "12345,123.4,50.6,12345#";
String answerV = "4.10,4.15,4.13,4.05,4.18,0#";
Master Code
#include <Wire.h>
int esc = 0;
int throttle = 80;
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("I2C Master ready!");
esc = throttle * 100 / 180;
}
void loop() {
delay(500);
Serial.println("Receive data");
Wire.requestFrom(9,32);
String response = "";
Serial.println(Wire.available());
while (Wire.available())
{
char b = Wire.read();
response += b;
}
String dataString = response;
int hashIndex = dataString.indexOf('#');
String SportData = dataString.substring(0, hashIndex);
Serial.println(SportData);
String SDdata = String (esc) + "," + String(SportData);
Serial.println(SDdata);
}
Slave Code
#include <Wire.h>
byte ANSWERSIZE= 22;
String answer = "12345,123.4,50.6,12345#";
String answerV = "4.10,4.15,4.13,4.05,4.18,0#";
void setup() {
Wire.begin(9);
Wire.onRequest(requestEvent); // data request from Master
Serial.begin(115200);
Serial.println("I2C Slave ready!");
ANSWERSIZE = answer.length();
}
void requestEvent() {
byte response[ANSWERSIZE];
for (byte i=0;i<ANSWERSIZE;i++)
{
response[i] = (byte)answer.charAt(i);
}
Wire.write(response,sizeof(response));
}
void loop() {
delay(50);
}
Can someone please show me how this can be done?
A simple idea is to keep track of the number of times requestEvent() is called, and use that to decide what to send back to the master.
Here is the code (n.b. I took the liberty to optimise it a bit):
Master:
#include <Wire.h>
/**
* globals
*/
int esc = 0;
int throttle = 80;
char i2c_buffer[33];
/**
* setup & loop
*/
void setup()
{
Serial.begin(115200);
Wire.begin();
esc = throttle * 100 / 180;
i2c_buffer[32] = '\0';
Serial.println("I2C Master ready!");
}
void loop()
{
delay(500);
Wire.requestFrom(9, 32);
for (byte i = 0; i < 32 && Wire.available(); ++i)
{
i2c_buffer[i] = Wire.read();
if (i2c_buffer[i] == '#') {
i2c_buffer[i] = '\0';
break;
}
}
Serial.print(esc);
Serial.print(',');
Serial.println(i2c_buffer);
}
Slave:
#include <Wire.h>
/**
* globals
*/
const byte DATA_SIZE = 2;
String data[DATA_SIZE] = {
"12345,123.4,50.6,12345#",
"4.10,4.15,4.13,4.05,4.18,0#"
};
/**
* setup & loop
*/
void setup()
{
Serial.begin(115200);
Wire.begin(9);
Wire.onRequest(requestEvent); // data request from Master
Serial.println("I2C Slave ready!");
}
void loop()
{
delay(50);
}
/**
* help functions
*/
void requestEvent()
{
static byte req_number = 0;
Wire.write(reinterpret_cast<const unsigned char*>(data[req_number].c_str()),
data[req_number].length());
req_number = (req_number + 1) % DATA_SIZE;
}
Note: I don't have two Arduino devices, so I could not test this code. If you spot some bugs, report back and I'll fix them.

I2C between RPI and Arduino using Processing

Posted here is my code for my RPi master and Arduino slave project. I have an analog sensor connected to the Arduino and i am reading this data with Processing on the RPi. I am using Processing because I intend on generating a graph and waveform with the data. The code below seems to work, however, any slight movement of setup "disconnects" the slave device because I get the following message. "The device did not respond. Check the cabling and whether you are using the correct address." I have narrowed the problem down and found out that it always disconnects at the i2c.read();function. My question is whether there is some type of break function so that when this does happen processing moves on and tries again in the next iteration? Or if it is stuck in a loop is it waiting for some signal from the slave device? Does anyone have any suggestions on how to approach this?
Processing Code
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
byte[] in = i2c.read(1);
int accel = in[0];
println (accel);
}
}
Arduino Code
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 5;
int state = 0;
const int zInput = A0;
int zRawMin = 493;
int zRawMax = 530;
float acceleration;
int accel;
void setup() {
analogReference(EXTERNAL);
pinMode(13,OUTPUT);
Serial.begin(9600); // start serial for output
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address #8
Wire.onReceive(receiveData); // register event
Wire.onRequest(sendData);
Serial.println ("Ready");
}
void loop() {
int zRaw = ReadAxis (zInput);
acceleration = map (float(zRaw), float (zRawMin), float(zRawMax), -9.81, 9.81);
accel = int(acceleration);
//delay(100);
}
void receiveData(int byteCount)
{
while (0 < Wire.available())
{ // loop through all but the last
number = Wire.read(); // receive byte as a character
//Serial.print("data received");
Serial.println(number); // print the character
if (number==1)
{
if (state == 0)
{
digitalWrite(13,HIGH);
state = 1;
}
else
{
digitalWrite(13,LOW);
state = 0;
}
}
}
}
void sendData()
{
Wire.write(accel);
}
int ReadAxis(int axisPin)
{
long reading = 0;
int raw = analogRead(axisPin);
return raw;
}
Looks like a solution might be to use a try/catch block courtesy of #Kevin Workman. It works well for what I need it to do thx.
here is the updated Processing code.
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
try
{
byte[] in = i2c.read(1);
}
catch(Exception e)
{
i2c.endTransmission();
}
int accel = in[0];
println (accel);
}
}

Intel Edison not searching tweets

I was given a Intel Edison, with an integrated WiFi board, to mess around with and read some tweets. So far, I've downloaded the Twitter4j core .jar (version 4.0.2, latest as of today), and set up the Arduino-Processing communication.
Every time I try to execute a query (search tweets by hashtags, for instance) it says Error: api.twitter.com. I have verified that I am connected to the network, and that the network has no proxy issues with Twitter.
It stops working right after println("pre query").
Any ideas?
My Arduino sketch is as follows:
#include <WiFi.h>
#include <WiFiUdp.h>
#include <Ethernet.h>
int ledPin=13;
char ssid[] = "OnePlus One"; // the name of your network
char pass[] = "hugomario"; // your network password
int status = WL_IDLE_STATUS; // the Wifi radio's status
void setup()
{
Serial.println("inside setup");
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
Serial.println("\nconnecting ...");
status = WiFi.begin(ssid, pass);
// if you're not connected, stop here:
if ( status != WL_CONNECTED) {
Serial.println("Couldn't get a wifi connection");
while(true);
}
// if you are connected :
else {
Serial.print("Connected to the network");
}
}
void loop()
{
Serial.println("\ninside loop");
while(Serial.available()==0);
int val = Serial.read()- '0';
Serial.println(val);
if(val == 1)
{
Serial.println("LED IS ON");
digitalWrite(ledPin,HIGH);
delay(1000);
digitalWrite(ledPin,LOW);
}
else
{
Serial.println("LED IS OFF");
digitalWrite(ledPin,LOW);
}
}
My Processing sketch:
import processing.serial.*;
Serial port;
static String OAuthConsumerKey="kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO";
static String OAuthConsumerSecret="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
static String AccessToken= "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
static String AccessTokenSecret="Mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5";
String[] searchedTweets = new String[50];
ConfigurationBuilder cb = new ConfigurationBuilder();
Twitter twitter;
void setup() {
//Set the size of the stage, and the background to black.
size(200, 200);
background(0);
smooth();
port = new Serial (this, "COM5", 115200);
connectTwitter();
}
void connectTwitter() {
cb.setOAuthConsumerKey(" kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO ");
cb.setOAuthConsumerSecret(" kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO ");
cb.setOAuthAccessToken("124767053- kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO ");
cb.setOAuthAccessTokenSecret(" kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxO ");
cb.setHttpConnectionTimeout(100000);
twitter = new TwitterFactory(cb.build()).getInstance();
println("is twitter null? ");
println(twitter==null);
getSearchTweets();
}
void getSearchTweets() {
String queryStr = "#yolo";
try {
println("inside try");
Query query = new Query(queryStr);
// query.setRpp(10); //10 out of 100 results
query.count(10);
println("pre query");
QueryResult result = twitter.search(query);
println("post query");
ArrayList tweets = (ArrayList) result.getTweets();
println("tweets size= "+tweets.size());
for (int i=0; i<tweets.size (); i++) {
/*
Tweet t = (Tweet) tweets.get(i);
String user = t.getFromUser();
String msg = t.getText();
Date d = t.getCreatedAt();
*/
Status t = (Status) tweets.get(i);
String user = t.getUser().getName();
String msg = t.getText();
port.write('1');
searchedTweets[i] = user +": "+msg;
println(searchedTweets[i]);
}
}
catch (TwitterException e) {
println("Error: " + e.getMessage());
port.write('0');
}
}
void delay(int delay){
int time = millis();
while(millis()-time <= delay);
}

Resources