WebSocket works on PC but not on Android? - android

I'm trying to communicate with an ESP8266 WiFi chip from an Android device using WebSockets to remotely control some motors connected to an Arduino. First I prototyped using a PC & Python & set up a WebSocket server on the ESP8266...
ESP8266_server.ino
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
const char* ssid = "SKYNET";
const char* password = "yourdogsauntsmaidenname";
WebSocketsServer webSocket = WebSocketsServer(81);
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
//Serial.printf("[%u] get Message: %s\r\n", num, payload);
switch(type) {
case WStype_DISCONNECTED:
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
}
break;
case WStype_TEXT:
{
//Serial.printf("[%u] get Text: %s\r\n", num, payload);
String _payload = String((char *) &payload[0]);
Serial.print(_payload);
}
break;
case WStype_BIN:
{
hexdump(payload, lenght);
}
// echo data back to browser
webSocket.sendBIN(num, payload, lenght);
break;
}
}
void setup() {
// Set up serial comms
Serial.begin(115200);
// Set up WiFi
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
// Serial.print(".");
delay(200);
}
// Serial.println("");
// Serial.println("WiFi connected");
// Serial.println("IP address: ");
// Serial.println(WiFi.localIP());
delay(500);
// Set up web socket
// Serial.println("Start Websocket Server");
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
}
The WiFi chip is connecetd via a serial connection to an Arduino Mega which in turn parses the data to control some H-bridges for 2 DC motors. The Arduino also relays the data to the Arduino IDE serial monitor.
motor_control.ino
// Serial comms from Wemos EPS8622 to Arduino Mega
#include "SoftPWM.h"
// Outputs to PWM & H bridge direction
// PWMs:
// DC_pwm, left_pwm, right_pwm = 3, 4, 5
int pwm_out[] = {3, 4, 5};
const int num_pwm = sizeof(pwm_out) / sizeof(pwm_out[0]);
// H bridge direction control:
// right_2, right_1, left_2, left_1, dc_2, dc_1 = 6, 7, 8, 9, 10 ,11
int dir_pins[] = {6, 7, 8, 9, 10 , 11};
const int num_dir_pins = sizeof(dir_pins) / sizeof(dir_pins[0]);
// Input buffer from ESP8266
int in_buff[] = {0, 0};
const int num_in_buff = sizeof(in_buff) / sizeof(in_buff[0]);
void setup() {
// Set up serial comms
Serial.begin(115200); // Debug to Serial Monitor
Serial3.begin(115200); // From ESP8266
// Set up PWM pins
SoftPWMBegin();
for (int i = 0; i < num_pwm; i++)
{
SoftPWMSet(pwm_out[i], 0);
}
// Set up H bridge direction pins
for (int i = 0; i < num_dir_pins; i++)
{
pinMode(dir_pins[i], OUTPUT);
digitalWrite(dir_pins[i], LOW);
}
}
void loop() {
// Check input from EPS8266 & send it to the H bridges
while (Serial3.available() < num_in_buff){}
if (Serial3.available()) {
// read the incoming bytes
// in_buff[0] - direction flags
// in_buff[1] - PWM
Serial.println(".......");
Serial.println("In from ESP8266");
for (int i = 0; i < num_in_buff; i++){
in_buff[i] = Serial3.read();
Serial.println(in_buff[i]);
}
Serial.println(".......");
}
// Set direcions on H bridges
Serial.println("Direction pins");
for (int i = 0; i < num_dir_pins; i++)
{
digitalWrite(dir_pins[i], bitRead(in_buff[0], i));
Serial.print("pin ");
Serial.print(dir_pins[i]);
Serial.print(" : ");
Serial.print(digitalRead(dir_pins[i]));
Serial.println();
}
// PWM to motors
for (int i = 0; i < num_pwm; i++)
{
SoftPWMSet(pwm_out[i], in_buff[1]);
}
}
On the PC side I have some Python code that is set up as a WebSocket client that takes user input from the terminal & transmits to the ESP chip.
motor_control_WiFi.py
"""
Motor control over WiFi using Wemos EPS8266 & Mega board
Motor H-bridge direction flags
Both forwards - b'111001, d'57, ASCII 9
Both backwards - b'110110, d'54, ASCII 6
Clockwise (right) - b'111010, d'58, ASCII :
A/Clock (left) - b'110101, d'53, ASCII 5
"""
from ws4py.client.threadedclient import WebSocketClient
import time, requests
import struct
esp8266host = "ws://192.168.1.84:81/"
class DummyClient(WebSocketClient):
def opened(self):
print("Websocket open")
def closed(self, code, reason=None):
print("Connexion closed down", code, reason)
def received_message(self, m):
print(m)
if __name__ == '__main__':
try:
ws = DummyClient(esp8266host)
ws.connect()
print("Ready !")
direction = ""
while direction != "q":
direction = input("Direction: ")
if direction == "f":
payload = "9"
if direction == "b":
payload = "6"
if direction == "r":
payload = ":"
if direction == "l":
payload = "5"
ws.send(payload)
time.sleep(.20)
pwm_out = int(input("PWM: "))
pwm_out = struct.pack('<B', pwm_out)
ws.send(pwm_out)
time.sleep(.20)
print("Finished, close Websocket connexion now and exit script")
ws.send("0:0")
ws.close()
exit()
except KeyboardInterrupt:
ws.send("0:0")
ws.close()
This all works fine. So my next step was to make an Android app to do what my Python code is doing. I'm using the okhttp3 library & added implementation 'com.squareup.okhttp3:okhttp:3.6.0' to the Gradle build file & added internet permissions to the manifest.
MainActivity.java
package qdivision.org.websocketexample;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class MainActivity extends AppCompatActivity {
private Button start;
private TextView output;
private OkHttpClient client;
private final class EchoWebSocketListener extends WebSocketListener {
private static final int NORMAL_CLOSURE_STATUS = 1000;
#Override
public void onOpen(WebSocket webSocket, Response response) {
//webSocket.send("l");
webSocket.send(ByteString.decodeHex("23"));
webSocket.send(ByteString.decodeHex("32"));
webSocket.close(NORMAL_CLOSURE_STATUS, "Goodbye !");
}
#Override
public void onMessage(WebSocket webSocket, String text) {
output("Receiving : " + text);
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
output("Receiving bytes : " + bytes.hex());
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(NORMAL_CLOSURE_STATUS, null);
output("Closing : " + code + " / " + reason);
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
output("Error : " + t.getMessage());
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start = (Button) findViewById(R.id.start);
output = (TextView) findViewById(R.id.output);
client = new OkHttpClient();
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
start();
}
});
}
private void start() {
Request request = new Request.Builder().url("ws://192.168.1.84:81").build(); //"ws://echo.websocket.org"
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
}
private void output(final String txt) {
runOnUiThread(new Runnable() {
#Override
public void run() {
output.setText(output.getText().toString() + "\n\n" + txt);
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="qdivision.org.websocketexample.MainActivity">
<Button
android:id="#+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Start !"
android:layout_marginTop="40dp"
android:textSize="17sp"/>
<TextView
android:id="#+id/output"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/start"
android:layout_centerHorizontal="true"
android:textSize="16sp"
android:layout_marginTop="30dp"/>
</RelativeLayout>
When this is deployed I dont get any connection errors. The sent bytes are echoed back to the display & the client disconnects with no error. BUT I get no feed back via the Arduino Serial Monitor that anything has been sent!
What's missing here? How come no connection error if the bytes are not being sent/recieved?
Edit #1 I ran the Python code on the Android device from the Termux command line. The code runs, says the socket is open & lets me input direction & PWM but still nothing from the serial monitor.
Edit #2 I can ping the ESP8266 from the Android device using Termux with 0 package loss but still no data being sent by either the Python code or the app.
Edit #3 Python code now works from the Termux command line on the Android device (no idea how I made no changes, it just works now??!!??). The okhttp3 based app still sends no data.

Related

read html code made by arduino at android

I want to read html code of arduino web server.
I can make web server simply with from example 4. code is below.
#include <SoftwareSerial.h>
#include "WiFly.h"
#define SSID "yum2"
#define KEY "yum000000"
// check your access point's security mode, mine was WPA20-PSK
// if yours is different you'll need to change the AUTH constant, see the file WiFly.h for avalable security codes
#define AUTH WIFLY_AUTH_WPA2_PSK
int flag = 0;
// Pins' connection
// Arduino WiFly
// 2 <----> TX
// 3 <----> RX
SoftwareSerial wiflyUart(2, 3); // create a WiFi shield serial object
WiFly wifly(&wiflyUart); // pass the wifi siheld serial object to the WiFly class
void setup()
{
wiflyUart.begin(9600); // start wifi shield uart port
Serial.begin(9600); // start the arduino serial port
Serial.println("--------- WIFLY Webserver --------");
// wait for initilization of wifly
delay(1000);
wifly.reset(); // reset the shield
delay(1000);
//set WiFly params
wifly.sendCommand("set ip local 80\r"); // set the local comm port to 80
delay(100);
wifly.sendCommand("set comm remote 0\r"); // do not send a default string when a connection opens
delay(100);
wifly.sendCommand("set comm open *OPEN*\r"); // set the string that the wifi shield will output when a connection is opened
delay(100);
Serial.println("Join " SSID );
if (wifly.join(SSID, KEY, AUTH)) {
Serial.println("OK");
} else {
Serial.println("Failed");
}
delay(5000);
wifly.sendCommand("get ip\r");
char c;
while (wifly.receive((uint8_t *)&c, 1, 300) > 0) { // print the response from the get ip command
Serial.print((char)c);
}
Serial.println("Web server ready");
}
void loop()
{
if(wifly.available())
{ // the wifi shield has data available
if(wiflyUart.find("*OPEN*")) // see if the data available is from an open connection by looking for the *OPEN* string
{
Serial.println("New Browser Request!");
delay(1000); // delay enough time for the browser to complete sending its HTTP request string
// send HTTP header
wiflyUart.println("HTTP/1.1 200 OK");
wiflyUart.println("Content-Type: text/html; charset=UTF-8");
wiflyUart.println("Content-Length: 244"); // length of HTML code
wiflyUart.println("Connection: close");
wiflyUart.println();
// send webpage's HTML code
wiflyUart.print("<html>");
wiflyUart.print("<head>");
wiflyUart.print("<title>My WiFI Shield Webpage</title>");
wiflyUart.print("</head>");
wiflyUart.print("<body>");
wiflyUart.print("<h1>Hello World!</h1>");
wiflyUart.print("<h3>10 20 30 40 50</h3>");
wiflyUart.print("Yahoo! Google");
wiflyUart.print("<br/><button>My Button</button>");
wiflyUart.print("</body>");
wiflyUart.print("</html>");
}
}
}
the web server work well.
I wrote simple android code to read html is below.
package com.example.http;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private TextView tv;
String urlAddress = "192.168.0.10"; // doesn't show
// String urlAddress = "http://www.kma.go.kr/weather/main.jsp#1159068000"; // work well
Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView)findViewById(R.id.textView1);
Button b = (Button)findViewById(R.id.button1);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadHtml();
}
});
}
void loadHtml() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
final StringBuffer sb = new StringBuffer();
try {
URL url = new URL(urlAddress);
HttpURLConnection conn =
(HttpURLConnection) url.openConnection();
if (conn != null) {
conn.setConnectTimeout(2000);
conn.setUseCaches(false);
if (conn.getResponseCode()
== HttpURLConnection.HTTP_OK) {
BufferedReader br
= new BufferedReader(new InputStreamReader
(conn.getInputStream()));
while (true) {
String line = br.readLine();
if (line == null) break;
sb.append(line + "\n");
}
br.close();
}
conn.disconnect();
}
Log.d("test", sb.toString());
handler.post(new Runnable() {
#Override
public void run() {
tv.setText(sb.toString());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
}
}
It work very well with String urlAddress = "http://www.kma.go.kr/weather/main.jsp#1159068000";
but it doesn't show when using
String urlAddress = "192.168.0.10"; instead of before one.
the 192.168.0.10 is allocated ip of arduino from DHCP that i can check on serial monitor.
there is any way to read html from arduino web server??
Your urlAddress isn't a URL, it's just an IP address. You should fully qualify the address with the protocol and the path you want to land on, for example:
String urlAddress = "http://192.168.0.10/";
I would expect you're getting a MalformedURLException.

Sending String from Arduino to Processing app on Android over Bluetooth

I’m pretty new to Arduino and Processing and and this is also my first time asking a question about coding on the internet.
I’m currently trying to do the following thing for a school project: I want to send a String with data from sensors on my Arduino to a android phone or tablet over bluetooth.
For simplicity’s sake I reduced the code in complexity, removing every part of my code that isn’t trying to facilitate the transfer of a String from Arduino to Processing on Android. The following code is simply trying to send the String “S01E” to the processing app on my phone, saving the String into my “String info” and displaying that string in form of a text(info, 20, 110); element.
Additional Info:
Arduino bluetooth module is a “Bluefruit EZ-Ling BLuetooth Shield”.
Phone is Samsung Galaxy S8.
Processing App is generated with Android mode of Processing.
My phone is successfully paired with the arduino over bluetooth.
The code compiles successfully, but it only shows my text(“test text”, 20, 120); on my phone, but not my text(info, 20, 110);, which I assume means that the String is not being received and the info String stays empty.
How can i proceed from here? Are there some obvious problems in my code. And how can I properly debug my code with the weird stack of technologies that I use?
Processing Code:
import netP5.*;
import android.content.Intent;
import android.os.Bundle;
import ketai.net.bluetooth.*;
import ketai.ui.*;
import ketai.net.*;
KetaiBluetooth bt;
boolean isConfiguring = true;
String info = "";
KetaiList klist;
ArrayList devicesDiscovered = new ArrayList();
// States of the two sensors
int B1in = 0;
int B2in = 0;
//********************************************************************
// The following code is required to enable bluetooth at startup.
//********************************************************************
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bt = new KetaiBluetooth(this);
}
void onActivityResult(int requestCode, int resultCode, Intent data) {
bt.onActivityResult(requestCode, resultCode, data);
}
void setup() {
size(displayWidth, displayHeight);
frameRate(10);
orientation(PORTRAIT);
background(255);
stroke(160);
fill(50);
//start listening for BT connections
bt.start();
//at app start select device…
isConfiguring = true;
}
void draw() {
background(255);
text(info,20,110);
text("test text",20,120);
println(info);
}
void onKetaiListSelection(KetaiList klist)
{
String selection = klist.getSelection();
bt.connectToDeviceByName(selection);
//dispose of list for now
klist = null;
}
//Call back method to manage data received
void onBluetoothDataEvent(String who, byte[] data) {
if (isConfiguring)
return;
//received
info = new String(data);
}
And here is my Arduino code:
#include <SoftwareSerial.h>
SoftwareSerial bt(2,3); // RX, TX
// Enthält den String, der an den PC geschickt wird
String data = "S01E";
// Serielle Schnittstelle einrichten, pinModes setzen
void setup() {
bt.begin(9600);
Serial.begin(9600);
}
void loop() {
Serial.println(data);
}
I also asked the same Question on discourse.processing.org. The link to my Question:
https://discourse.processing.org/t/sending-string-from-arduino-to-processing-app-on-android-over-bluetooth/6106
Could you try this?
void setup() {
isConfiguring = true;
size(displayWidth, displayHeight);
frameRate(10);
orientation(PORTRAIT);
background(255);
stroke(160);
fill(50);
//start listening for BT connections
bt.start();
//at app start select device…
isConfiguring = false;
}
It seems the function your using to retrieve data from the Bluetooth event is simply returning because of your Boolean flag is never changing from true.

My android phone is not sending signals to the arduino uno or maybe the arduino uno card is not communicating to the servo motor sg90

I am uploading the code of both the android-studio as well as the arduino uno.. It seems right but somehow it doesn't work
Android Studio code :
package com.example.chintan.doorlock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private final String DEVICE_ADDRESS = "00:21:13:01:ED:10"; //MAC Address of Bluetooth Module
private final UUID PORT_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
private BluetoothDevice device;
private BluetoothSocket socket;
private OutputStream outputStream;
private InputStream inputStream;
Thread thread;
byte buffer[];
boolean stopThread;
boolean connected = false;
String command;
Button lock_state_btn, bluetooth_connect_btn;
TextView lock_state_text;
ImageView lock_state_img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lock_state_btn = (Button) findViewById(R.id.lock_state_btn);
bluetooth_connect_btn = (Button) findViewById(R.id.bluetooth_connect_btn);
lock_state_text = (TextView) findViewById(R.id.lock_state_text);
lock_state_img = (ImageView) findViewById(R.id.lock_state_img);
bluetooth_connect_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
if(BTinit()) //initialises bluetooth
{
BTconnect(); //connects android code to arduino
beginListenForData();
// The code below sends the number 3 to the Arduino asking it to send the current state of the door lock so the lock state icon can be updated accordingly
command = "3";
try
{
outputStream.write(command.getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
});
lock_state_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
if(connected == false)
{
Toast.makeText(getApplicationContext(), "Please establish a connection with the bluetooth servo door lock first", Toast.LENGTH_SHORT).show();
}
else
{
command = "1";
try
{
outputStream.write(command.getBytes()); // Sends the number 1 to the Arduino. For a detailed look at how the resulting command is handled, please see the Arduino Source Code
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
});
}
void beginListenForData() // begins listening for any incoming data from the Arduino
{
final Handler handler = new Handler();
stopThread = false;
buffer = new byte[1024];
Thread thread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopThread)
{
try
{
int byteCount = inputStream.available();
if(byteCount > 0)
{
byte[] rawBytes = new byte[byteCount];
inputStream.read(rawBytes);
final String string = new String(rawBytes, "UTF-8");
handler.post(new Runnable()
{
public void run()
{
if(string.equals("3"))
{
lock_state_text.setText("Lock State: LOCKED"); // Changes the lock state text
lock_state_img.setImageResource(R.drawable.locked_icon); //Changes the lock state icon
}
else if(string.equals("4"))
{
lock_state_text.setText("Lock State: UNLOCKED");
lock_state_img.setImageResource(R.drawable.unlocked_icon);
}
}
});
}
}
catch (IOException ex)
{
stopThread = true;
}
}
}
});
thread.start();
}
#Override
protected void onStart()
{
super.onStart();
}
}
And this is my arduino source code :
//Android-controlled Arduino Bluetooth Servo Door Lock by uscv
#include <Servo.h>
#include <EEPROM.h>
Servo servo;
char state;
void setup() {
// put your setup code here, to run once:
servo.attach(7);
if(EEPROM.read(0) == 1) // Reads the EEPROM value stored to know what state the door lock was in before it was last turned off
{ // An EEPROM value of 1 means UNLOCKED and a value of 2 means LOCKED
servo.write(0); // Rotates the servo to the unlocked position
delay(200);
}
else if(EEPROM.read(0) == 2)
{
servo.write(75); // Rotates the servo to the locked position
delay(200);
}
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() > 0)
{
char data;
data = Serial.read(); // The variable data is used to store the value sent by the Android app
switch(data)
{
case '1':
if(EEPROM.read(0) == 1) //An EEPROM value of 1 means it is currently unlocked
{
EEPROM.write(0, 2); // Writes the number 2 to address 0 on the Arduino's EEPROM. This value will be used by the Arduino to remember the last state the door lock was in
Serial.print("3"); // Sends the number 3 to the Android app. To see what this does, please see the Android Studio Project file
servo.write(75);
delay(15);
}
else if(EEPROM.read(0) == 2) //An EEPROM value of 2 means it i currently locked
{
EEPROM.write(0, 1); // Writes the number 1 to address 0 on the Arduino's EEPROM. This value will be used by the Arduino to remember the last state the door lock was in
Serial.print("4"); // Sends the number 4 to the Android app. The number sent will be used by the app to update the locked/unlocked icon
servo.write(0);
delay(15);
}
break;
case '3':
if(EEPROM.read(0) == '1')
{
Serial.print("4");
}
else if(EEPROM.read(0) == '2')
{
Serial.print("3");
}
break;
}
}
}
So, first the android app will start bluetooth, then connect to the arduino uno card and then perform the following functions:
1. "3" sent from android phone to arduino
2. received either "4" or "3" based on its status from arduino uno to android
3. Change the lock image on the android phone
4. send "1" from the android phone to the arduino
5. Change the status of the servo motor sg90 from its current position
Now, my android application is error-free and connects to the arduino uno and also is able to start the bluetooth of the phone. It establishes the connection but does not change the position of the servo motor sg90. I dont understand the problem what should we do?
You are calling EEPROM.read() before initializating the EEPROM. In other words for example in your setup() you are checking whether you EEPROM address 0 contains a certain value rather than initialization it with a certain value. Then
in your loop(), again you are checking whether EEPROM address contains a certain value before any value is written to the EEPROM and thus you will never reach the EEPROM write part because your if statements always returns false. So, start first by writing a value to EEPROM address 0.

Using data received from Arduino via Bluetooth

I am working on an Android app that will constantly receive data from an Arduino HC-05 and store it in a database. For now I am focusing on receiving the data properly (so just displaying it on the screen is my next step).
I have followed this guide (PDF) to setup a basic app that will receive data from the Arduino. However, it doesn't include a section about using the received data. I've tried adding two lines of code to the handleMessage function in order to display the received data on screen, but I don't see any difference in the textview (it stays "Hello World!").
I know that my Arduino is sending the data just fine, since on another app called "Serial Bluetooth Terminal" it is displayed properly. Here is the code for the Handler class:
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
byte[] writeBuf = (byte[]) msg.obj;
int begin = (int)msg.arg1;
int end = (int)msg.arg2;
switch(msg.what) {
case 1:
String writeMessage = new String(writeBuf);
writeMessage = writeMessage.substring(begin, end);
// 2 lines of code I've added here:
TextView tempTextView = (TextView) findViewById(R.id.text_view);
tempTextView.setText(writeMessage);
break;
}
}
};
Aside from the 2 lines, the code is basically the same as the final stage of the guide. And here is the code for the Arduino (which currently just sends "1 2.00 3.00" over and over):
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(0, 1); //RX|TX
int Temp= 1;
float Ph = 2;
float Ec = 3;
void setup() {
Serial.begin(9600);
BTSerial.begin(9600);
}
void loop() {
Serial.print(Temp);
Serial.print(" ");
delay(100);
Serial.print(Ph);
Serial.print(" ");
delay(100);
Serial.print(Ec);
Serial.print(" ");
delay(100);
Serial.print('\n');
if(Serial.available())
BTSerial.write(Serial.read());
}

Send about ten two digit numbers at a time to a Bluetooth device at random intervals

I am building a BLE remote controller application.
I am paring a BLE device with the Android phone with the tested and working code below.
Intent intentOpenBluetoothSettings = new Intent();
intentOpenBluetoothSettings.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(intentOpenBluetoothSettings);
I want to connect to one of the devices in the paired list, and I know the name, which is always the same.
Later, I want to send about ten two digit numbers at a time to that device at random intervals (from a listener for a button), and I don't need any information back. Simplex communication only, Android phone to BLE device.
#Override
public void uiDeviceFound(final BluetoothDevice device, final int rssi, final byte[] record )
{
String msg ;
String deviceName = device.getName() ;
String redRacer = "Red Racer" ;
if (redRacer.equals(deviceName))
{
boolean status ;
status = mBleWrapper.connect(device.getAddress().toString()) ;
if (status == false)
{
msg = "Sorry, could not connect to Red Racer" ;
Toast.makeText(SecondaryActivity.this,msg,Toast.LENGTH_SHORT).show() ;
}
else
{
msg = "Connected to Red Racer" ;
Toast.makeText(SecondaryActivity.this,msg + " " + deviceName + " " + redRacer,Toast.LENGTH_SHORT).show() ;
}
}
}
During my research to resolve the issue I found this brief, but informative article on the differences between pairing and bonding as far as BLE is concerned:
https://piratecomm.wordpress.com/2014/01/19/ble-pairing-vs-bonding/
Giving credit where credit is due. The above code which resolved my issue was taken from Getting Started with Bluetooth Low Energy (O'REILLY), although the code copied directly from their book continually crashed the activity whenever it was called. After correcting the problems, as per the above code, it works flawlessly. Now that the connection is made, I have to push my control code out the established link to the Simblee chip on my slave board.
Overall the code is what I would define as plug-in reusable code which I think will be applicable to others who might want the same functionality. I will post the complete code, once I have it up and running.
package com.my_android_app.my_android_app;
import android.app.Activity ;
import android.content.Intent ;
import android.content.SharedPreferences ;
import android.content.pm.PackageManager ;
import android.os.Bundle ;
import android.os.Handler ;
import android.support.v7.app.AppCompatActivity ;
import android.util.Log ;
import android.view.Gravity ;
import android.view.View ;
import android.widget.Button ;
import android.widget.TextView ;
import android.widget.Toast ;
import java.util.List ;
import java.util.UUID ;
import java.util.Calendar ;
import android.bluetooth.BluetoothAdapter ;
import android.bluetooth.BluetoothDevice ;
import android.bluetooth.BluetoothGatt ;
import android.bluetooth.BluetoothGattCharacteristic ;
import android.bluetooth.BluetoothGattService ;
public class BLE_Test_Activity extends AppCompatActivity {
public BLE_Test_Activity.mSensorState mState ;
private enum mSensorState {IDLE, ACC_ENABLE, ACC_READ} ;
boolean connectedTo = false ;
boolean okButtonClicked = false ;
boolean receivedRSSI = false ;
private byte[] mRawValue = null ;
private int mIntValue = 0 ;
private String mAsciiValue = "" ;
private String mStrValue = "" ;
private String mLastUpdateTime = "" ;
private boolean mNotificationEnabled = false ;
private final String LOGTAG = "BLETEST" ;
private final String TARGET_BLE = "My BLE Device" ;
private String gattList = "" ;
private int rssi_1 = 0 ;
private int rssi_2 = 0 ;
private int rssi_3 = 0 ;
private int rssi_4 = 0 ;
private int valueRSSI = 0 ;
private String mDeviceRSSI ;
private TextView mDeviceStatus ;
private TextView mDeviceRssiView ;
private String mDeviceAddress ;
private static final long SCANNING_TIMEOUT = 5 * 1000; /* 5 seconds */
// The UUID variable values below are only applicable to the RFD77101 BLE chip.
// Enter values here which are applicable to the BLE device you are using.
private static final UUID
UUID_SIMBLEE_SERVICE = UUID.fromString("0000fe84-0000-1000-8000-00805f9b34fb") ,
UUID_SIMBLEE_CHARACTERISTIC_2 = UUID.fromString("2d30c083-f39f-4ce6-923f-3484ea480596") ;
private boolean mScanning = false ;
private Handler mHandler = new Handler() ;
private BleWrapper mBleWrapper = null ; // Add this line to instantiate the BLE wrapper
private BluetoothGattCharacteristic mCharacteristic = null ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState) ;
setContentView(R.layout.activity_ble__test_) ;
connectViewsVariables() ;
final String dataSentMessage = "Your " + TARGET_BLE + " put your transmitted message here." ;
mBleWrapper = new BleWrapper(this, new BleWrapperUiCallbacks.Null() {
#Override
public void uiDeviceFound(final BluetoothDevice device, final int rssi, final byte[] record) {
if (TARGET_BLE.equals(device.getName())) {
if (mBleWrapper.connect(device.getAddress())) {
// Toast.makeText(BLE_Test_Activity.this, device.getAddress(), Toast.LENGTH_SHORT).show(); // This is included for debugging purposes
} else {
Toast.makeText(BLE_Test_Activity.this, "Sorry, could not connect to " + TARGET_BLE, Toast.LENGTH_SHORT).show();
}
}
} // ********************** uiDeviceFound *************************************
public void uiDeviceConnected(final BluetoothGatt gatt, final BluetoothDevice device) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mDeviceStatus.setText ("connected ") ;
mDeviceRssiView.setText ("measuring .") ;
connectedTo = true;
}
});
} // ********************** uiDeviceConnected *************************************
public void uiDeviceDisconnected(final BluetoothGatt gatt, final BluetoothDevice device) // Takes about 20 seconds to display disconnected,
{ // then more than thirty minutes to reconnect.
runOnUiThread(new Runnable() {
#Override
public void run() {
mDeviceStatus.setText ("disconnected") ;
mDeviceRssiView.setText("disconnected") ;
connectedTo = false;
}
});
} // ********************** uiDeviceDisconnected *************************************
#Override
public void uiCharacteristicForService( BluetoothGatt gatt,
BluetoothDevice device,
BluetoothGattService service,
List<BluetoothGattCharacteristic> chars)
{
super.uiCharacteristicForService(gatt, device, service, chars);
for (BluetoothGattCharacteristic c : chars)
{
String charName = BleNamesResolver.resolveCharacteristicName(c.getUuid().toString()) ;
gattList += "Characteristic: " + charName + "\n" ;
}
} // ********************** uiCharacteristicForService *************************************
public void uiNewRssiAvailable(final BluetoothGatt gatt, final BluetoothDevice device, final int rssi) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (rssi_4 == 0)
{
mDeviceRSSI = "measuring ....." ;
mDeviceRssiView.setText(mDeviceRSSI) ;
}
if (rssi_3 == 0)
{
mDeviceRSSI = "measuring ...." ;
mDeviceRssiView.setText(mDeviceRSSI) ;
}
if (rssi_2 == 0)
{
mDeviceRSSI = "measuring ..." ;
mDeviceRssiView.setText(mDeviceRSSI) ;
}
if (rssi_1 == 0)
{
mDeviceRSSI = "measuring .." ;
mDeviceRssiView.setText(mDeviceRSSI) ;
}
rssi_4 = rssi_3 ;
rssi_3 = rssi_2 ;
rssi_2 = rssi_1 ;
rssi_1 = rssi ;
if (rssi_4 != 0) {
valueRSSI = (rssi_1 + rssi_2 + rssi_3 + rssi_4) / 4 ; // This is a simple moving average to filter out noise
mDeviceRSSI = (valueRSSI) + " dBm" ;
mDeviceRssiView.setText(mDeviceRSSI) ;
}
receivedRSSI = true ;
}
}) ;
if (okButtonClicked)
{
okButtonClicked = false ;
// Build up newValue with the data you want to send out the BLE link.
// I have hard coded 0202 just for testing purposes.
// Make sure the contents of newValue is Hex only 0 - 9, A - F
String newValue = "0202" ;
byte[] dataToWrite = parseHexStringToBytes(newValue) ;
BluetoothGattCharacteristic mCharacteristic ;
mCharacteristic = gatt.getService(UUID_SIMBLEE_SERVICE).getCharacteristic(UUID_SIMBLEE_CHARACTERISTIC_2) ;
mBleWrapper.writeDataToCharacteristic(mCharacteristic, dataToWrite) ;
}
} // *************************** uiNewRssiAvailable ***********************************************
#Override
public void uiNewValueForCharacteristic(BluetoothGatt gatt,
BluetoothDevice device,
BluetoothGattService service,
BluetoothGattCharacteristic ch,
String strValue,
int intValue,
byte[] rawValue,
String timestamp)
{
super.uiNewValueForCharacteristic(gatt, device, service, ch, strValue, intValue, rawValue, timestamp);
for (byte b:rawValue)
{
Log.d(LOGTAG,"Val: + b") ;
}
} // ********************** uiNewValueForCharacteristic *************************************
#Override
public void uiGotNotification( BluetoothGatt gatt,
BluetoothDevice device,
BluetoothGattService service,
BluetoothGattCharacteristic characteristic)
{
super.uiGotNotification(gatt, device, service, characteristic) ;
String ch = BleNamesResolver.resolveCharacteristicName(characteristic.getUuid().toString()) ;
Log.d(LOGTAG,"uiGotNotification: " + ch) ;
} // *************************** uiNewValueForCharacteristic *************************************
} ) ; // *************************** new BleWrapper **************************************************
if (!mBleWrapper.checkBleHardwareAvailable()) {
Toast.makeText(this, "No BluetoothLE compatible hardware detected", Toast.LENGTH_SHORT).show() ;
finish() ;
} // ********************** checkBleHardwareAvailable *************************************
Button activity6Button = (Button) findViewById(R.id.button6); // Green check mark button
activity6Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (connectedTo)
{
okButtonClicked = true ;
if (receivedRSSI)
{
Toast toast = Toast.makeText(BLE_Test_Activity.this, dataSentMessage, Toast.LENGTH_SHORT) ;
TextView v = (TextView) toast.getView().findViewById(android.R.id.message) ;
if (v != null) v.setGravity(Gravity.CENTER) ;
toast.show() ;
receivedRSSI = false ;
}
}
SharedPreferences prefs = getSharedPreferences("saveUserSettings", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit() ;
editor.putString("AppIsOn", "yes") ;
editor.apply() ;
}
}) ; // ********************** green check mark *************************************
Button activity7Button = (Button) findViewById(R.id.button7); // Blue back arrow
activity7Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setResult(Activity.RESULT_CANCELED) ; // Page 60 Sams
finish() ;
}
}) ; // ********************** back arrow *************************************
} // ********************************** onCreate ********************************************
public byte[] parseHexStringToBytes(final String hex) {
String tmp = hex.substring(2).replaceAll("[^[0-9][a-f]]", "") ;
byte[] bytes = new byte[tmp.length() / 2] ; // every two letters in the string are one byte finally
String part = "" ;
for(int i = 0; i < bytes.length; ++i) {
part = "0x" + tmp.substring(i*2, i*2+2) ;
bytes[i] = Long.decode(part).byteValue() ;
}
return bytes ;
} // ********************** parseHexStringToBytes *************************************
#Override
protected void onResume() {
super.onResume();
if (!mBleWrapper.isBtEnabled()) // Check for Bluetooth enabled on each resume
{
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) ;
startActivity(enableBtIntent) ;
Toast.makeText(BLE_Test_Activity.this, "Sorry but BluetoothLE is not supported on your phone", Toast.LENGTH_SHORT).show() ;
finish() ;
}
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(BLE_Test_Activity.this, "mBleWrapper.isBtEnabled", Toast.LENGTH_SHORT).show() ;
finish() ;
return ;
}
connectedTo = false ;
mBleWrapper.initialize() ;
mDeviceStatus.setText ("searching ...") ;
mDeviceRssiView.setText("searching ...") ;
mBleWrapper.startScanning() ;
} // ************************************ onResume **********************************************
#Override
protected void onStart() {
super.onStart();
} // *********************************** onStart *******************************
#Override
protected void onPause() {
connectedTo = false ;
super.onPause() ;
mBleWrapper.stopScanning() ;
mBleWrapper.diconnect() ;
mBleWrapper.close() ;
} // ********************** onPause *************************************
#Override
protected void onStop() {
SharedPreferences prefs = getSharedPreferences("saveUserSettings", MODE_PRIVATE) ;
SharedPreferences.Editor editor = prefs.edit() ;
editor.putString("AppIsOn", "no") ;
editor.apply() ;
mBleWrapper.stopScanning() ;
mBleWrapper.diconnect() ;
mBleWrapper.close() ;
super.onStop() ;
} // ********************** onStop *************************************
#Override
protected void onDestroy() {
SharedPreferences prefs = getSharedPreferences("saveUserSettings", MODE_PRIVATE) ;
SharedPreferences.Editor editor = prefs.edit() ;
editor.putString("AppIsOn", "no") ;
editor.apply() ;
mBleWrapper.stopScanning() ;
mBleWrapper.diconnect() ;
mBleWrapper.close() ;
super.onDestroy() ;
} // ********************** onDestroy *************************************
private void connectViewsVariables() {
mDeviceStatus = (TextView) findViewById(R.id.peripheral_status) ;
mDeviceRssiView = (TextView) findViewById(R.id.peripheral_rssi) ;
} // ********************** connectViewsVariables ********************************
} // ***************************** BLE_Test_Activity *****************************
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/ble_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:background="#FFFFFF"
tools:context="com.my_android_app.my_android_app.BLE_Test_Activity">
<TextView
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/peripheral_status"
android:gravity="center"
android:layout_marginTop="10dp"
android:layout_below="#+id/textView20"
android:layout_toStartOf="#+id/button39" />
<TextView
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/peripheral_rssi"
android:layout_marginLeft="200dp"
android:layout_marginTop="10dp"
android:layout_below="#+id/textView20" />
<Button
android:layout_width="50dp"
android:layout_height="50dp"
android:textAllCaps="false"
style="#style/Widget.AppCompat.Button.Borderless"
android:id="#+id/button7"
android:background="#drawable/returnicon"
android:layout_alignParentBottom="true"
android:layout_toEndOf="#+id/button39"
android:layout_marginStart="46dp" />
<Button
android:layout_width="50dp"
android:layout_height="50dp"
android:textAllCaps="false"
style="#style/Widget.AppCompat.Button.Borderless"
android:id="#+id/button6"
android:background="#drawable/checkmark"
android:layout_alignParentBottom="true"
android:layout_toStartOf="#+id/button39"
android:layout_marginEnd="44dp" />
</RelativeLayout>
Resources used by this demo.
https://www.bluetooth.com/develop-with-bluetooth/developer-resources-tools/app-acc-2 Download the Bluetooth Application Accelerator kit here, it contains several classes you will need to make this demo work, along with working Java code you can use in you app.
The BLE Demo app included in this kit is formatted for Android Studio thankfully. The BLE Demo app is excellent. In addition to being built around the BLE wrapper which is part of the the Applicaton Accelerator, the BLE Demo drills down into your BLE devices and displays all parameters and their values. The value of this can not be underestimated because in my case, the manufacturer of the BLE device I am using did not even document the UUIDs for the services and characteristics I needed to write to.
https://github.com/microbuilder/IntroToBLE Here is the source code from the excellent book 'Getting Started with Bluetooth Low Energy', O'REILLY. If all you want to do is read and write to a BLE device, this book contains far to much information, especially the marketing information for BLE, however the tutorial for Android development is excellent. Be aware that there are mistakes in the sample code in the book, and the sample code is not the same, but is similar as per this download.
https://evothings.com/2.1/doc/tutorials/how-to-connect-to-ble-devices.html This is an excellent tutorial on connecting with a BLE device with JavaScript which is useless of course for a Java program, however the connection methodology is the same. Also this tutorial explains in simple terms the sequence of events which are required to connect to a BLE device.
https://piratecomm.wordpress.com/category/bluetooth-le Here is a brief, but excellent article on Pairing and Bonding, relative to BLE devices.
Usage instructions:
Install the BLE Demo app from the Bluetooth application accelerator onto your Android phone.
Copy several classes from the BLE Demo app and put them into your app.
These classes are: BleWrapper, BleNamesResolver, BleDefinedUUIDs, BleWrapperUiCallbacks and FetchAddressIntentService.
Create a new empty activity in your app which you will use to place switches, seek bars etc. whose values you wish to send out the BLE link.
Copy and paste the BLE_JAVA into the class created by the new activity you just created.
Replace every occurrence of my_android_app with whatever is applicable for your app.
Replace every occurrence of BLE_Test_Activity with whatever is applicable for your activity.
For the string private final String TARGET_BLE = "My BLE Device" , put the device name of your target device at "My BLE Device" .
In the section private static final UUID, you will need to enter the UUID values applicable to your device. You can use the BLE Demo app to find them if you do not know what they are.
Copy and paste the BLE_XML into the XML file which was just created, and replace every occurrence of my_android_app with whatever is applicable for your app.
Replace every occurrence of BLE_Test_Activity with whatever is applicable for your activity.
I have included a stripped down version of my manifest for an example which I feel has the necessary ingredients for the BLE implementation.
Now you can put the switches, seek bars, etc. into the new activity you just created, and put the values of those controls in the string, 'newValue' which will be the data which will be sent out via BLE.
I hope I have included all necessary steps, if not please let me know so that I can make the applicable changes.
Here is the answer to my own question which was, is there any copy an paste code to implement a simple open loop control system with BLE, with the phone being the master which sends control codes to a BLE slave which can control several real world devices, like motors, lights, heaters, etc.
First of all, I realize an open loop control system is the least desirable control system there is, but in my case the Simblee RFD77101 does not have a characteristic which will return the value written to it, so a closed loop control system is not possible.
Eventually I would like to embellish this code to include read capabilities, etc. but that is not a current priority for me.
Finally, I am a complete newbie at Android/Java development, so if you have any comments or questions, please be nice, and I will do what I can.

Categories

Resources