I configured ESP8266-01 as an access point. After connecting to ESP wifi network as a client, on-click events of the android app try to send data using AsyncTask which uses a socket to send data to ESP88266 (access point). by on-click events, I can send led/on or led/off commands. hence led will toggle when I press two buttons. I used a toast in public void onPostExecute(final String Data) in AsyncTask to determine what data is sent back by the server(ESP) to the android app as its client. I have expected to receive a kind of JSON response containing "on" or "off" as acknowledge since ESP Sends the response to the client(client.println(s);) when I click on buttons I can turn led on or off but received data on public void onPostExecute(final String Data) section of the app always contains null.ESP default access point IP address is 192.168.4.1 then using a browser I can send 192.168.4.1/led/on to turn led on and the browser immediately shows{"data":{"message":"success","value":"off"}}as JSON response but I need to have an acknowledgment for the designed android app.
How can I get any kind of acknowledgment from ESP in my android app?
Any help is appreciated.
here are ESP code from Arduino IDE and MainActivity code of the android app.
ESP code:
#include<ESP8266WiFi.h>
// WiFi Definitions
const char* ssid = "DigitalCalendar";
const char* password = "Esp8266Test"; // has to be longer than 7 chars
const char* value = "";
int ledPin = 2; // GPIO 2
WiFiServer server(80);
void setup() {
Serial.begin(9600);
delay(10);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH); // turn on
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password, 1, false);
server.begin();
}
void loop() {
// Check of client has connected
WiFiClient client = server.available();
if(!client) {
return;
}
// Read the request line
String request = client.readStringUntil('\r');
Serial.print(request+'\r');
// Match request
if(request.indexOf("/led/on") != -1) {
digitalWrite(ledPin, HIGH);
value = "on";
} else if (request.indexOf("/led/off") != -1) {
digitalWrite(ledPin, LOW);
value = "off";
}
client.flush();
// JSON response
String s = "HTTP/1.1 200 OK\r\n";
s += "Content-Type: application/json\r\n\r\n";
s += "{\"data\":{\"message\":\"success\",\"value\":\"";
s += value;
s += "\"}}\r\n";
s += "\n";
// Send the response to the client
client.println(s);
delay(1);
//Serial.println("Client disconnected");
// The client will actually be disconnected when the function returns and the client object is destroyed
}
MAIN ACTIVITY code:
public class MainActivity extends AppCompatActivity {
private static final int LOCATION = 1;
Button btn1,btn2;
String command;
String networkSSID = "Esp8266TestNet";
String networkPass = "Esp8266Test";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=findViewById(R.id.btn1);
btn2=findViewById(R.id.btn2);
//------------------------------------------------------
btn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
command="/led/on\r";
send_request(command);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
command="/led/off\r";
send_request(command);
}
});
}
public void send_request(String message) {
send_request sr = new send_request();
sr.execute(message);
}
class send_request extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... message) {
try {
/*note : ip address must be in Quotation mark*/
/*note : port doesn't need to be inside the Quotation mark*/
Socket s = new Socket(/*ip address :*/"192.168.4.1",/*port :*/ 80);
PrintWriter printWriter = new PrintWriter(s.getOutputStream());
printWriter.write(message[0]);
printWriter.flush();
printWriter.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public void onPostExecute(final String Data) {
/*Data is what you receive from your server*/
Log.e("my_Data","Data is : " + Data);
Toast.makeText(MainActivity.this, Data, Toast.LENGTH_SHORT).show();
}
}
protected void onStart() {
super.onStart();
//Assume you want to read the SSID when the activity is started
tryToReadSSID();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == LOCATION){
//User allowed the location and you can read it now
tryToReadSSID();
}
}
private String tryToReadSSID() {
String ssid="no ssid";
//If requested permission isn't Granted yet
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//Request permission from user
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION);
}else{//Permission already granted
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if(wifiInfo.getSupplicantState() == SupplicantState.COMPLETED){
ssid = wifiInfo.getSSID();//Here you can access your SSID
}
}
return ssid;
}
}
Related
I am currently trying to send a message from my Android-Smartphone to a raspberry pi.
I implemented an Android-Client by the example code given here:
Really simple TCP client
I changed the ip-address an port so it works with my server running on the pi. This server is written in c and before switching to android, I implemented a C-Client which worked so far without any problems.
The server just needs to receive a message and then it prints it and stops, so it is very simple.
EDIT 3
I created new outputs for debugging and analysis, I may got an idea now what is not working. As far as I can see, the SendMessageTask is never executed.
The Server outputs are now:
Success - create socket
Success - Binding
Listening
Success - Accept
now it stalls, "reading..." is never printed! (should happen in the while loop)
In Android I receive the following neccessary outputs:
D/TCP Client: C: Connecting...
D/TcpOptimizer: TcpOptimizer-ON
--> Connection happened
When I push the Send button:
D/myMessage1: button pushed
D/myMessage: testing
But I do not get the messages which should be logged in the SendMessageTask
When I click the disconnect button the server prints:
Client disconnected
And now Android logs:
D/RESPONSE FROM SERVER: S: Received Message: 'null'
D/sendMessageTask: try to send message
D/TcpClient: Cannot send --> mBufferOut is null
Therefore my guess is, the SendMessageTask never runs until it fails due to disconnection, but why?
Edit 3 - End
This is the (edited) server code:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
int main(){
int welcomeSocket, newSocket, read_size;
char buffer[10000];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);
if (welcomeSocket == -1) {
printf("Could not create socket\n");
}else {
printf("Success - create socket\n");
}
/*---- Configure settings of the server address struct ----*/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7891);
serverAddr.sin_addr.s_addr = INADDR_ANY;
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
if(bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0){
printf("Error - Binding\n");
}else {
printf("Success - Binding\n");
}
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
if(newSocket < 0){
printf("Error - Accept\n");
}else {
printf("Success - Accept\n");
}
while( (read_size = recv(newSocket, buffer, 10000, 0)) > 0){
write(newSocket, buffer, strlen(buffer));
printf("reading...");
}
if(read_size == 0){
printf("Client disconnected");
fflush(stdout);
}
else if(read_size == -1){
printf("Error - recv failed");
}
return 0;
}
I am not quite sure if the parameters in
welcomeSocket = socket(AF_INET, SOCK_STREAM, 0);
are still correct?
The Client-Code in Android is:
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static final String TAG = TcpClient.class.getSimpleName();
public static final String SERVER_IP = "192.168.4.1"; //server IP address
public static final int SERVER_PORT = 7891;
// message to send to the server
private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private PrintWriter mBufferOut;
// used to read messages from the server
private BufferedReader mBufferIn;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TcpClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* #param message text entered by client
*/
public void sendMessage(final String message) {
Runnable runnable = new Runnable() {
#Override
public void run() {
if (mBufferOut != null) {
Log.d(TAG, "Sending: " + message);
mBufferOut.println(message);
mBufferOut.flush();
}else{
Log.d(TAG, "Cannot send --> mBufferOut is null");
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
/**
* Close the connection and release the members
*/
public void stopClient() {
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.d("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
//sends the message to the server
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//receives the message which the server sends back
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in this while the client listens for the messages sent by the server
while (mRun) {
/*
mServerMessage = mBufferIn.readLine();
if (mServerMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(mServerMessage);
}
*/
}
Log.d("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
//class at on AsyncTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
And my (edited) Mainactivity including the AsyncTask for connection is
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;
public class MyActivity extends AppCompatActivity {
private TextView mTextMessage;
private TextView myAwesomeTextView;
private TcpClient mTcpClient;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(R.string.title_home);
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myActivity);
mTextMessage = (TextView) findViewById(R.id.message);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
myAwesomeTextView = (TextView)findViewById(R.id.editText);
//TCP connect
new ConnectTask().execute("");
//Buttons
final Button button_Send = findViewById(R.id.button_Send);
button_Send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Set text (debugging)
myAwesomeTextView.setText("My Awesome Text");
Log.d("myMessage1", "button pushed ");
//sends the message to the server
String message = "testing\0";
//String message = "testing\n\r";
if (mTcpClient != null) {
new SendMessageTask().execute(message);
//not needed just for debugging
Log.d("myMessage", "testing ");
}
}
});
final Button button_Disconnect = findViewById(R.id.button_Disconnect);
button_Disconnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mTcpClient != null) {
mTcpClient.stopClient();
}
}
});
}
#Override
protected void onPause() {
super.onPause();
if (mTcpClient != null) {
// disconnect
new DisconnectTask().execute();
}
}
/**
* Sends a message using a background task to avoid doing long/network operations on the UI thread
*/
public class SendMessageTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
// send the message
mTcpClient.sendMessage(params[0]);
Log.d("sendMessageTask", "try to send message ");
return null;
}
#Override
protected void onPostExecute(Void nothing) {
super.onPostExecute(nothing);
//nothing to do yet
}
}
/**
* Disconnects using a background task to avoid doing long/network operations on the UI thread
*/
public class DisconnectTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
// disconnect
mTcpClient.stopClient();
mTcpClient = null;
return null;
}
#Override
protected void onPostExecute(Void nothing) {
super.onPostExecute(nothing);
//nothing to do yet
}
}
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
#Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object and
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
Log.d("test", "response " + values[0]);
//process server response here....
}
}
}
EDIT #2 (failing behaviour still remains)
uncommented while(mRun) Loop in run-method of TcpClient
--> thought maybe the socket is closed by finally before the message has been sent.
moved the initial connection into onCreate(), so the button will just
handle the sending and the connection is established before.
removed closing the socket after sending the message
I managed to got this working.
I changed the line
new SendMessageTask().execute(message);
to
new SendMessageTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);
This got the sending working.
I also changed the server code to this:
#define MAX 2048
#define PORT 7891
#define SA struct sockaddr
// Function designed for chat between client and server.
void communicate(int sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n');
// and send that buffer to client
write(sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed..\n");
exit(0);
}
else
printf("Server listening...\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..\n");
// Function for chatting between client and server
communicate(connfd);
// After chatting close the socket
if(close(sockfd) < 0){
printf("Error - closing socket...\n");
}
else{
printf("Socket successfully closed..\n");
}
}
I am developing an android application which requires me to send data to a Bluetooth Low Energy device.After the connection event is successful and after I receive a call back message I want to change the activity and display new GUI where on switch click I want to send data to connected device. The problem is after the activity has changed my BluetoothGatt becomes null and BluetoothGattCharacteristic also becomes null and i am not able to send the data. how can I solve this issue? Below is my code main class which onResume calls the connection activity and connects to first available device and after connection is successful it receives callback message and changes the activity.
public class MainActivity extends Activity implements BluetoothLeUart.Callback {
public TextView messages;
private BluetoothLeUart uart;
public void writeLine(final CharSequence text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
messages.append(text);
messages.append("\n");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
messages = (TextView) findViewById(R.id.messages);
// Initialize UART.
uart = new BluetoothLeUart(getApplicationContext());
messages.setMovementMethod(new ScrollingMovementMethod());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
protected void onResume() {
super.onResume();
writeLine("Scanning for devices ...");
uart.registerCallback(this);
uart.connectFirstAvailable();
}
#Override
protected void onStop() {
super.onStop();
uart.unregisterCallback(this);
uart.disconnect();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
// UART Callback event handlers.
// UART Callback event handlers.
#Override
public void onConnected(BluetoothLeUart uart) {
// Called when UART device is connected and ready to send/receive data.
//messages.append("connected2");
writeLine("Connected!");
Intent intent = new Intent(MainActivity.this,SwitchClass.class);
startActivity(intent);
}
}
This is my codes BluetoothLeUart class which does connection activity and gives callback message.
public class BluetoothLeUart extends BluetoothGattCallback implements BluetoothAdapter.LeScanCallback {
// UUIDs for UART service and associated characteristics.
public static UUID UART_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID TX_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
public static UUID RX_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
// UUID for the UART BTLE client characteristic which is necessary for notifications.
public static UUID CLIENT_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
// UUIDs for the Device Information service and associated characeristics.
public static UUID DIS_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MANUF_UUID = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
public static UUID DIS_MODEL_UUID = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
public static UUID DIS_HWREV_UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
public static UUID DIS_SWREV_UUID = UUID.fromString("00002a28-0000-1000-8000-00805f9b34fb");
// Internal UART state.
private Context context;
private WeakHashMap<Callback, Object> callbacks;
private BluetoothAdapter adapter;
private BluetoothGatt gatt;
private BluetoothGattCharacteristic tx;
private BluetoothGattCharacteristic rx;
private boolean connectFirst;
private boolean writeInProgress; // Flag to indicate a write is currently in progress
// Queues for characteristic read (synchronous)
private Queue<BluetoothGattCharacteristic> readQueue;
// Interface for a BluetoothLeUart client to be notified of UART actions.
public interface Callback {
public void onConnected(BluetoothLeUart uart);
public void onConnectFailed(BluetoothLeUart uart);
public void onDisconnected(BluetoothLeUart uart);
public void onReceive(BluetoothLeUart uart, BluetoothGattCharacteristic rx);
public void onDeviceFound(BluetoothDevice device);
public void onDeviceInfoAvailable();
}
public BluetoothLeUart(Context context) {
super();
this.context = context;
this.callbacks = new WeakHashMap<Callback, Object>();
this.adapter = BluetoothAdapter.getDefaultAdapter();
this.gatt = null;
this.tx = null;
this.rx = null;
this.disManuf = null;
this.disModel = null;
this.disHWRev = null;
this.disSWRev = null;
this.disAvailable = false;
this.connectFirst = false;
this.writeInProgress = false;
this.readQueue = new ConcurrentLinkedQueue<BluetoothGattCharacteristic>();
}
// Send data to connected UART device.
public void sendbyte(byte[] data) {
if (tx == null || data == null || data.length == 0) {
// Do nothing if there is no connection or message to send.
return;
}
// Update TX characteristic value. Note the setValue overload that takes a byte array must be used.
tx.setValue(data);
writeInProgress = true; // Set the write in progress flag
gatt.writeCharacteristic(tx);
// ToDo: Update to include a timeout in case this goes into the weeds
while (writeInProgress); // Wait for the flag to clear in onCharacteristicWrite
gatt.readCharacteristic(rx);
}
// Send data to connected UART device.
public void send(String data) {
if (data != null && !data.isEmpty()) {
sendbyte(data.getBytes(Charset.forName("UTF-8")));
}
}
// Register the specified callback to receive UART callbacks.
public void registerCallback(Callback callback) {
callbacks.put(callback, null);
}
// Unregister the specified callback.
public void unregisterCallback(Callback callback) {
callbacks.remove(callback);
}
// Disconnect to a device if currently connected.
public void disconnect() {
if (gatt != null) {
gatt.disconnect();
}
gatt = null;
tx = null;
rx = null;
}
// Stop any in progress UART device scan.
public void stopScan() {
if (adapter != null) {
adapter.stopLeScan(this);
}
}
// Start scanning for BLE UART devices. Registered callback's onDeviceFound method will be called
// when devices are found during scanning.
public void startScan() {
if (adapter != null) {
adapter.startLeScan(this);
}
}
// Connect to the first available UART device.
public void connectFirstAvailable() {
// Disconnect to any connected device.
disconnect();
// Stop any in progress device scan.
stopScan();
// Start scan and connect to first available device.
connectFirst = true;
startScan();
}
// Handlers for BluetoothGatt and LeScan events.
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// Connected to device, start discovering services.
if (!gatt.discoverServices()) {
// Error starting service discovery.
connectFailure();
}
else {
notifyOnConnected(this);
}
}
else {
// Error connecting to device.
connectFailure();
}
}
else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
// Disconnected, notify callbacks of disconnection.
rx = null;
tx = null;
notifyOnDisconnected(this);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
// Notify connection failure if service discovery failed.
if (status == BluetoothGatt.GATT_FAILURE) {
connectFailure();
return;
}
// Save reference to each UART characteristic.
tx = gatt.getService(UART_UUID).getCharacteristic(TX_UUID);
rx = gatt.getService(UART_UUID).getCharacteristic(RX_UUID);
// Save reference to each DIS characteristic.
disManuf = gatt.getService(DIS_UUID).getCharacteristic(DIS_MANUF_UUID);
disModel = gatt.getService(DIS_UUID).getCharacteristic(DIS_MODEL_UUID);
disHWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_HWREV_UUID);
disSWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_SWREV_UUID);
// Add device information characteristics to the read queue
// These need to be queued because we have to wait for the response to the first
// read request before a second one can be processed (which makes you wonder why they
// implemented this with async logic to begin with???)
readQueue.offer(disManuf);
readQueue.offer(disModel);
readQueue.offer(disHWRev);
readQueue.offer(disSWRev);
// Request a dummy read to get the device information queue going
// gatt.readCharacteristic(disManuf);
// Setup notifications on RX characteristic changes (i.e. data received).
// First call setCharacteristicNotification to enable notification.
if (!gatt.setCharacteristicNotification(rx, true)) {
// Stop if the characteristic notification setup failed.
connectFailure();
return;
}
// Next update the RX characteristic's client descriptor to enable notifications.
BluetoothGattDescriptor desc = rx.getDescriptor(CLIENT_UUID);
if (desc == null) {
// Stop if the RX characteristic has no client descriptor.
connectFailure();
return;
}
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
if (!gatt.writeDescriptor(desc)) {
// Stop if the client descriptor could not be written.
connectFailure();
return;
}
// Notify of connection completion.
notifyOnConnected(this);
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
notifyOnReceive(this, characteristic);
}
#Override
public void onCharacteristicRead (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//Log.w("DIS", characteristic.getStringValue(0));
// Check if there is anything left in the queue
BluetoothGattCharacteristic nextRequest = readQueue.poll();
if(nextRequest != null){
// Send a read request for the next item in the queue
// gatt.readCharacteristic(nextRequest);
}
else {
// We've reached the end of the queue
disAvailable = true;
// notifyOnDeviceInfoAvailable();
}
}
else {
//Log.w("DIS", "Failed reading characteristic " + characteristic.getUuid().toString());
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// Log.d(TAG,"Characteristic write successful");
}
writeInProgress = false;
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
// Stop if the device doesn't have the UART service.
if (!parseUUIDs(scanRecord).contains(UART_UUID)) {
//main.writeLine("Parse UUID failed...");
//main.messages.append("Parse UUID failed...");
return;
}
// Connect to first found device if required.
if (connectFirst) {
// Stop scanning for devices.
stopScan();
// Prevent connections to future found devices.
connectFirst = false;
// Connect to device.
gatt = device.connectGatt(context, true, this);
}
}
// Private functions to simplify the notification of all callbacks of a certain event.
private void notifyOnConnected(BluetoothLeUart uart) {
for (Callback cb : callbacks.keySet()) {
if (cb != null) {
cb.onConnected(uart);
}
}
}
private List<UUID> parseUUIDs(final byte[] advertisedData) {
List<UUID> uuids = new ArrayList<UUID>();
int offset = 0;
while (offset < (advertisedData.length - 2)) {
int len = advertisedData[offset++];
if (len == 0)
break;
// main.writeLine(advertisedData.toString());
int type = advertisedData[offset++];
switch (type) {
case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
//main.writeLine("case 02,03...");
// main.messages.append("case 02,03...");
while (len > 1) {
int uuid16 = advertisedData[offset++];
uuid16 += (advertisedData[offset++] << 8);
len -= 2;
uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", uuid16)));
}
break;
case 0x06:// Partial list of 128-bit UUIDs
case 0x07:// Complete list of 128-bit UUIDs
// Loop through the advertised 128-bit UUID's.
//main.writeLine("case 06,07...");
// main.messages.append("case 06,07...");
while (len >= 16) {
try {
// Wrap the advertised bits and order them.
ByteBuffer buffer = ByteBuffer.wrap(advertisedData, offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
long mostSignificantBit = buffer.getLong();
long leastSignificantBit = buffer.getLong();
uuids.add(new UUID(leastSignificantBit,
mostSignificantBit));
} catch (IndexOutOfBoundsException e) {
// Defensive programming.
//Log.e(LOG_TAG, e.toString());
continue;
} finally {
// Move the offset to read the next uuid.
offset += 15;
len -= 16;
}
}
break;
default:
//main.writeLine("case default...");
// main.messages.append("case default");
offset += (len - 1);
break;
}
}
return uuids;
}
}
Here is my class from where I send the data
public class SwitchClass extends Activity {
public TextView messages;
public Switch Switch1;
public byte[] switchData = {'U','1','1','1','0','0','2','Z'};
private BluetoothLeUart uart;
public void writeLine(final CharSequence text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
messages.append(text);
messages.append("\n");
//messages.setText("anirudh");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.switchlayout);
Switch1 = (Switch) findViewById(R.id.switch1);
uart = new BluetoothLeUart(getApplicationContext());
Switch1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
switchString = new String(switchData);
writeLine(switchString);
// send this array 8 bytes to BLE
sendData(switchString);
}
}
});
public void sendData(String sendVal) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(sendVal.toCharArray(), 0, 8);
uart.send(stringBuilder.toString());
}
You are creating a service from this activity and you are destroying it onStop
so your service is now been disconnected , so automatically you cant get bluetoothgatt and adapter for it
I suggest you to have child fragment inside you activity so your service will stay alive and you can have as many fragment you want to display the thing !!
Hopes this will help you !!
you can visit https://github.com/captain-miao/bleYan, It's a simple BLE library and example.
I also got exactly the same error like yours. In my case I comment out or deleted the following line under onServiceDiscover method. It works suddenly.It may not be the answer, Hope it will give you some clue to solve.
disManuf = gatt.getService(DIS_UUID).getCharacteristic(DIS_MANUF_UUID);
disModel = gatt.getService(DIS_UUID).getCharacteristic(DIS_MODEL_UUID);
disHWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_HWREV_UUID);
disSWRev = gatt.getService(DIS_UUID).getCharacteristic(DIS_SWREV_UUID);
readQueue.offer(disManuf);
readQueue.offer(disModel);
readQueue.offer(disHWRev);
readQueue.offer(disSWRev);
You must set to synchronized your BluetoothGatt Object like
public void setBluetoothGatt(BluetoothGatt gatt) {
synchronized (this) {
this.bluetoothGatt = gatt;
}
}
because BluetoothGatt throw DeadObject Exception when you change the Activity
I have a problem on android. I have an application that asks the user for the local Ip address (from the device's interface) and another remote address. The application has to bind to the specified local address and connect to the remote address. Quite simple, but, indeed, bind does not work ass i expected..
I added the following permissions on the manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
The source code is the following one:
public class MainActivity extends Activity
{
String Tag = "TAG";
private int LOCAL_PORT = 4444;
private int REMOTE_PORT = 80;
private EditText LOCAL;
private EditText REMOTE;
private Button Connect;
private TextView STATUS;
private Context context = this;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LOCAL = (EditText) findViewById(R.id.editText1);
REMOTE = (EditText) findViewById(R.id.editText2);
Connect = (Button) findViewById(R.id.button1);
Connect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
BotleneckHandle WORK;
Toast.makeText(getApplicationContext(), "Proceeding to connect",
Toast.LENGTH_SHORT).show();
/*
if(LOCAL.getText().toString() == null || REMOTE.getText().toString() == null || LOCAL.getText().toString().equals(" ") || REMOTE.getText().toString().equals(" ") || LOCAL.getText().toString().equals("") || REMOTE.getText().toString().equals(""))
Toast.makeText(context, "Wrong parameters", 2000);
else
{
Toast.makeText(getApplicationContext(), "Proceeding to connect",Toast.LENGTH_SHORT).show();
}*/
WORK = new BotleneckHandle();
WORK.execute();
}
});
STATUS = (TextView) findViewById(R.id.textView1);
}
private class BotleneckHandle extends AsyncTask <Void , Void , String>
{
Socket Skt = null;
String ReturnStatemente = new String();
SocketAddress localAddr = new InetSocketAddress(LOCAL.getText().toString(), LOCAL_PORT);
protected void onPreExecute(){ }
protected String doInBackground(Void... params)
{
try
{
String s=new String();
s+= "Local="+LOCAL.getText().toString()+":"+LOCAL_PORT+" Remote="+REMOTE.getText().toString()+":"+REMOTE_PORT; //so far so good, Confirmed by debug
Toast.makeText(getApplicationContext(), s,Toast.LENGTH_SHORT).show(); //Does not show anything due the fact that i didn't published it as an assync task update..
//binding to a local address
Skt.bind(localAddr); //cannot make the bind :-/
//connecting to remote host
Skt=new Socket(REMOTE.getText().toString(), REMOTE_PORT); //if bind is comment, still does not work.. I bet
ReturnStatemente = "Connected";
}
catch (UnknownHostException e)
{
e.printStackTrace();
Toast.makeText(context, "Unknown remote host", 2000);
ReturnStatemente = "Not Connected";
}
catch (IOException e)
{
e.printStackTrace();
Toast.makeText(context, "Connection fail", 2000);
ReturnStatemente = "Not Connected";
}
finally{try {
Skt.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}}
return ReturnStatemente;
}
protected void onPostExecute(String result) { STATUS.setText(" CONECTION STATUS == " + result); }
}
}
What am i doing wrong on bind? As far as i see, and as i searched for its good.. Did i miss something?
kind regards
You're trying to call bind on a variable before you assigned anything to it. So its still null. That isn't going to work. You need to create an instance of Socket before you can call methods on it.
I am trying to get data from Onyx2(Fingertip Oximeter) via Bluetooth using Health Device Profile and sample, which can be found at Android Developers site. But I am getting the following error
E/BluetoothEventLoop.cpp(432): onHealthDeviceConnectionResult: D-Bus error: org.bluez.Error.HealthError (Error getting remote SDP records).
What can be a reason of this problem?
BTW, approximately 1 time out of 50, I get the data.
// Callbacks to handle connection set up and disconnection clean up.
private final BluetoothProfile.ServiceListener mBluetoothServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEALTH) {
mBluetoothHealth = (BluetoothHealth) proxy;
if (Log.isLoggable(TAG, Log.DEBUG))
Log.d(TAG, "onServiceConnected to profile: " + profile);
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEALTH) {
mBluetoothHealth = null;
}
}
};
private final BluetoothHealthCallback mHealthCallback = new BluetoothHealthCallback() {
// Callback to handle application registration and unregistration events. The service
// passes the status back to the UI client.
public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
int status) {
if (status == BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE) {
mHealthAppConfig = null;
sendMessage(STATUS_HEALTH_APP_REG, RESULT_FAIL);
} else if (status == BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS) {
mHealthAppConfig = config;
sendMessage(STATUS_HEALTH_APP_REG, RESULT_OK);
} else if (status == BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE ||
status == BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS) {
sendMessage(STATUS_HEALTH_APP_UNREG,
status == BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS ?
RESULT_OK : RESULT_FAIL);
}
}
// Callback to handle channel connection state changes.
// Note that the logic of the state machine may need to be modified based on the HDP device.
// When the HDP device is connected, the received file descriptor is passed to the
// ReadThread to read the content.
public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
int channelId) {
if (Log.isLoggable(TAG, Log.DEBUG))
Log.d(TAG, String.format("prevState\t%d ----------> newState\t%d",
prevState, newState));
if (prevState == BluetoothHealth.STATE_CHANNEL_CONNECTING &&
newState == BluetoothHealth.STATE_CHANNEL_CONNECTED) {
if (config.equals(mHealthAppConfig)) {
mChannelId = channelId;
sendMessage(STATUS_CREATE_CHANNEL, RESULT_OK);
(new ReadThread(fd)).start();
} else {
sendMessage(STATUS_CREATE_CHANNEL, RESULT_FAIL);
}
} else if (prevState == BluetoothHealth.STATE_CHANNEL_CONNECTING &&
newState == BluetoothHealth.STATE_CHANNEL_DISCONNECTED) {
sendMessage(STATUS_CREATE_CHANNEL, RESULT_FAIL);
} else if (newState == BluetoothHealth.STATE_CHANNEL_DISCONNECTED) {
if (config.equals(mHealthAppConfig)) {
sendMessage(STATUS_DESTROY_CHANNEL, RESULT_OK);
} else {
sendMessage(STATUS_DESTROY_CHANNEL, RESULT_FAIL);
}
}
}
};
// Initiates application registration through {#link
// BluetoothHDPService}.
Button registerAppButton = (Button) findViewById(R.id.button_register_app);
registerAppButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
sendMessage(BluetoothHDPService.MSG_REG_HEALTH_APP,
HEALTH_PROFILE_SOURCE_DATA_TYPE);
}
});
// Initiates application unregistration through {#link
// BluetoothHDPService}.
Button unregisterAppButton = (Button) findViewById(R.id.button_unregister_app);
unregisterAppButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
sendMessage(BluetoothHDPService.MSG_UNREG_HEALTH_APP, 0);
}
});
// Initiates channel creation through {#link BluetoothHDPService}. Some
// devices will
// initiate the channel connection, in which case, it is not necessary
// to do this in the
// application. When pressed, the user is asked to select from one of
// the bonded devices
// to connect to.
Button connectButton = (Button) findViewById(R.id.button_connect_channel);
connectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mAllBondedDevices = (BluetoothDevice[]) mBluetoothAdapter
.getBondedDevices().toArray(new BluetoothDevice[0]);
if (mAllBondedDevices.length > 0) {
int deviceCount = mAllBondedDevices.length;
if (mDeviceIndex < deviceCount)
mDevice = mAllBondedDevices[mDeviceIndex];
else {
mDeviceIndex = 0;
mDevice = mAllBondedDevices[0];
}
String[] deviceNames = new String[deviceCount];
int i = 0;
for (BluetoothDevice device : mAllBondedDevices) {
deviceNames[i++] = device.getName();
}
SelectDeviceDialogFragment deviceDialog = SelectDeviceDialogFragment
.newInstance(deviceNames, mDeviceIndex);
deviceDialog.show(getFragmentManager(), "deviceDialog");
}
}
});
// Initiates channel disconnect through {#link BluetoothHDPService}.
Button disconnectButton = (Button) findViewById(R.id.button_disconnect_channel);
disconnectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disconnectChannel();
}
});
registerReceiver(mReceiver, initIntentFilter());
}
// Sets up communication with {#link BluetoothHDPService}.
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
mHealthServiceBound = true;
Message msg = Message.obtain(null,
BluetoothHDPService.MSG_REG_CLIENT);
msg.replyTo = mMessenger;
mHealthService = new Messenger(service);
try {
mHealthService.send(msg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to register client to service.");
e.printStackTrace();
I remember that Android HDP demo app had some problem about not closing bluetooth connections when terminated.
One test that you can do to verify this is:
Turn off bluetooth of your android.
Turn it on again.
Pair with the health device (in android settings)
Start your android application.
Try to connect and transfer data with health device.
If these steps works consistently when repeated, i'm almost sure it has something to do with the app not releasing resources like i sad before.
I'm trying to integrate the Twilio client into a larger application. Everything seems to work fine until I call device.connect(parameters, connectionListener). I get the 31100 Generic Malformed Request error and that's it.
On the same device, using the same Twilio account and the same Twilio application, the sample code supplied with the Twilio Android SDK (MonkeyPhone) works perfectly.
I can't find any more details about what the error means or what are the possible causes. While I'm assuming that I'm sending invalid data, I don't see how is that possible. The Capability Token is OK, I've verified it against the one generated in the MonkeyPhone sample app. Creating a Device works fine, no errors. The error is thrown even when I'm not sending any parameters in the connect() method. The onConnecting() method of the ConnectionListener gets called, but then the onDisconnected(Connection inConnection, int inErrorCode, String inErrorMessage) is called with the Malformed Request error.
The code for the Voice TwiML is working fine, it's just a simple PHP script generating the most simple <Dial> verb possible:
<Response>
<Dial>someone</Dial>
</Response>
Other specific information... I'm running another service in my application, used to do various other operations. Could this interfere in some way? Also, I'm using a trial account and I'm living in Romania, where calling real phone numbers is not supported (but I'm not using phone numbers anyway). Could this affect me in any way?
I apologize in advance for throwing the huge wall of code, but I hope a second pair of eyes can spot something wrong. This is the version of the code most similar to the MonkeyPhone sample. The only difference is that I'm using an AsyncTask to get the capability token (the JsonAsyncRequestWithError class.
public class MonkeyPhone implements Twilio.InitListener, DeviceListener {
private static final String TAG = "MonkeyPhone";
private Context context;
private Device device;
private Connection connection;
public MonkeyPhone(Context context) {
this.context = context;
Twilio.initialize(context, this /* Twilio.InitListener */);
}
#Override
/* Twilio.InitListener method */
public void onInitialized() {
Log.d(TAG, "Twilio SDK is ready");
// the Emulator has a somewhat unique "product" name
String clientName = "doug";
HttpGet get = new HttpGet("http://teamphoenix.zzl.org/capability.php?ClientName=" + clientName);
JsonAsyncRequestWithError asyncRequestWithError = new JsonAsyncRequestWithError(context, "test", new AsyncRequestWithErrorListener() {
#Override
public void onResult(AsyncRequestResponse response, Object destination) {
createDevice(response.getMessage());
}
#Override
public void onErrorResult(AsyncRequestResponse response, Object destination) {
}
});
asyncRequestWithError.execute(get);
}
public void createDevice(String token) {
try {
device = Twilio.createDevice(token, this /* DeviceListener */);
Intent intent = new Intent(context, SpringshotPhoneActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
device.setIncomingIntent(pendingIntent);
} catch (Exception e) {
Log.e(TAG, "", e);
}
}
#Override
/* Twilio.InitListener method */
public void onError(Exception e) {
Log.e(TAG, "Twilio SDK couldn't start: " + e.getLocalizedMessage());
}
#Override
/* DeviceListener method */
public void onStartListening(Device inDevice) {
Log.i(TAG, "Device is now listening for incoming connections");
}
#Override
/* DeviceListener method */
public void onStopListening(Device inDevice) {
Log.i(TAG, "Device is no longer listening for incoming connections");
}
#Override
/* DeviceListener method */
public void onStopListening(Device inDevice, int inErrorCode, String inErrorMessage) {
Log.i(TAG, "Device is no longer listening for incoming connections due to error " + inErrorCode + ": " + inErrorMessage);
}
#Override
/* DeviceListener method */
public boolean receivePresenceEvents(Device inDevice) {
return false; // indicate we don't care about presence events
}
#Override
/* DeviceListener method */
public void onPresenceChanged(Device inDevice, PresenceEvent inPresenceEvent) {
}
public void connect(String phoneNumber) {
Map<String, String> parameters = new HashMap<String, String>(1);
parameters.put("PhoneNumber", phoneNumber);
/// ---------------- THIS IS THE CALL THAT FAILS ------------------------------------//
connection = device.connect(parameters, null /* ConnectionListener */);
if (connection == null)
Log.w(TAG, "Failed to create new connection");
}
public void disconnect() {
if (connection != null) {
connection.disconnect();
connection = null;
}
}
public void handleIncomingConnection(Device inDevice, Connection inConnection) {
Log.i(TAG, "Device received incoming connection");
if (connection != null)
connection.disconnect();
connection = inConnection;
connection.accept();
}
#Override
protected void finalize() {
if (connection != null)
connection.disconnect();
if (device != null)
device.release();
}
}
Thank you very much!
I figured out the problem. Apparently, I had to read the InputStream from the server using the UTF-8 encoding (even if there are no special characters in the token).
char[] buf = new char[1024];
InputStream is = response.getEntity().getContent();
StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(is, "UTF-8");
int bin;
while ((bin = in.read(buf, 0, buf.length)) >= 0) {
out.append(buf, 0, bin);
}
return out.toString();