Managing HC05 and HC 06 devices.

Hello, Here’s my situation:
I’ve will have five digital scales I’ve hacked equipped with HC-05 bluetooth modules. As soon as they are turned on, they start spewing their current weight every 500ms. If the weight doesn’t change for 2 minutes they auto-power off. Other than changing the timeout and data rate, I can’t really change anything else.

I will have twelve data entry stations of my own design, each with an HC-05. At a user prompt (about every 20 seconds), I’d like to get the weight from the scale. Currently I have one scale and one station for testing.

When in use, there will always be only one station and one scale, but I don’t know which ones. I’m trying to figure out the best strategy for managing this. I’ve been messing around with commands for hours and I still don’t have a good feel for how things work.

I can do this to connect with the HC-05 in AT mode:

  • AT+RESET
  • AT+INIT
  • AT+INQ
  • parse result to extract address
  • AT+LINK=
  • Toggle “key” pin low, then high again. Data starts streaming in
  • How to pause comminications, then re-start?
  • If scale has turned on, how to best re-establish communications?

I’m assuming that the ROLE is already 1 (master) and the CMODE is 1 as well. INQM=1,1,8 so I will only look for one device and not spend more than ~10 seconds doing it. Passwords will all be “1234”.

I’m not sure about PAIR vs LINK vs BIND. If I’ve paired two devices, will they connect automatically? Is only one pair stored, or can each console store all the scales?

Is there any way to just connect to the first device found without having to parse address. This would be great.?

I’m also getting some odd behavior. Often when I send AT+STATUS? I get ERROR: (0) which is an “AT command error”.

I’ve read lots of data sheets and wikis, none of which seem to be comprehensive. There are many examples of simple code using these modules, but I have yet to find a really in-depth example which is relevant to my project.

I would also like to save some power when I don’t need data from bluetooth. I can of course power off the HC05, but I thought there should be a more elegant way. I tried AT+DISC, but it doesn’t seem to do anything, the data keeps streaming in until the scale turns off.

RyanN: There are many examples of simple code using these modules, but I have yet to find a really in-depth example which is relevant to my project.

That might be because bluetooth is not relevant to your project. You could be better off using an NRF24 network, which is cheaper, and more appropriate to the job.

The operative word there is "network"

And yes, an NRF24 consumes a hell of a lot less power than an HC-0x.

Thanks, while NRF24 looks cool, and I’m going to order some, I see some problems.

  • The scale I’m using only has a serial output and these seem to be SPI.
  • I could probably find a pin for another chip select but I’m almost out of pins on my mega without resorting to multiplexers. ( The legacy hardware I’m interfacing with has over 250 hall sensors)
  • These seem great for mesh and swarm networks which is exactly what I don’t have. I have one master one slave, just not always the same master and slave.
  • I’d like to be able to download data from my sampling stations to a PC. I couldn’t find any simple way to do this via NRF24

After fiddling with the modules last night, it seems like the HC05 can pair with a number of other devices. How many? You can get a count of pairs with AT+ADCN? and see if an address is in the list with AT+FSAD=. It seems like is a device is paired, it will connect automatically. The behavior when connecting still doesn’t make much sense to me. After sending AT+INIT… I start receiving data when I pull “KEY” low, then high again. Seems like I should just pull it low.

The scale I’m using only has a serial output and these seem to be SPI.

OK. I imagine that you can get serial to SPI but it probably requires a tiny Arduino, and isn’t worth the effort

. I have one master one slave, just not always the same master and slave.

I believe that comprises a network and I think I have seen examples of that with NRF24. I haven’t actually used my NRFs as bluetooth suffices

I’d like to be able to download data from my sampling stations to a PC. I couldn’t find any simple way to do this via NRF24

Yes I think that is best left to bluetooth. One Arduino collects the data by whatever means and relays to PC via bluetooth. And I withdraw my previous comment. NRFs are essentially better for Arduinos talking amongst themselves, and bluetooth is better for talking to the outside world. Your problem is that the scales are in the outside world, and you have a lot of them. Bluetooths essentially pair - i.e. one-to-one, and you need to pair sequentially.

RyanN:
After fiddling with the modules last night, it seems like the HC05 can pair with a number of other devices. How many? You can get a count of pairs with AT+ADCN? and see if an address is in the list with AT+FSAD=. It seems like is a device is paired, it will connect automatically. The behavior when connecting still doesn’t make much sense to me. After sending AT+INIT… I start receiving data when I pull “KEY” low, then high again. Seems like I should just pull it low.

This is all beyond me. I believe what you are saying is true but beyond the realms of normal usage.

This guy has done HC-05 auto connect

and might be able help.

Thanks,

I’ve got it working pretty well with my test scale and station. I don’t know how many pairings each HC05 can store, but it’s at least 6. Once paired, and everything is set up once. You can power up and connect with:
AT+INIT
AT+LINK=

I’m impressed.

I guess the hints are there if you read the data with a sufficiently suspicious mind, but I couldn’t see them and I have never heard of this being done. I have been drawing up a proto shield with two HC-05s on board but stopped in the light of your posts!

My situation is a lot simpler. I am looking at two separate bluetooth operations in the one loop cycle. Solution: use two two blueteeth, each in “normal usage”. Now I’m not so sure.

You can power up and connect with:
AT+INIT
AT+LINK=

What does this mean? Do you mean that you are arranging connection to one scale only at power up, but using a stored selection?

I thought your objective was:

One bluetooth polls many and retrieves data from those that are sending data.

The secret is thus in the ability to configure the HC-05 from within the datalogging programme rather than use a separate config programme, i.e. enter AT mode on the fly.

Even if you are not polling many, I now understand that you are incorporating AT config in a programme. I guess P Cantin is doing this too. While I recommended him, I have not progressed to actually using him myself.

My objective is to have a 1:1 connection. One scale with one sampling station. My difficulty is that when an operator takes his gear in the field, I don’t know which station and which scale they will take. When they start up the station, there will be only one scale to connect to, but I don’t know which one.

I’m not sure I understand your application. You have two HC05s. Are they communicating with each other, or with separate devices?

I’m not really polling. As soon as the two bluetooth modules connect, there is a constant and unending stream of values sent from the slave (HC06) to the master (HC05). Most of the time I ignore it, but if I need a weight, I clear the Serial buffer and parse the next value I get.
I’ve got it set up to be non-blocking go I just call getData() once per loop and when it returns true I know I have parsed a weight value.

It may not make too much sense outside the larger context, but here are my files. Keep in mind that they are at the just got it working stage, an I probably need to go through them and make the code more efficient.
The .h file:

#ifndef _LIMNO_BT_H_
#define _LIMNO_BT_H_

#define BT_BUFFER_SIZE 100

#include <Arduino.h>
#include <HardwareSerial.h>


enum hc05_result :uint8_t{
 // Mostly error codes
 BT_AT_COMMAND_ERROR = 0,
 BT_DEFAULT_RESULT = 1,
 BT_PSKEY_WRITE_ERROR = 2,
 BT_TOO_LONG = 3,
 BT_NO_DEV_NAME = 4,
 BT_NAP_TOO_LONG = 6,
 BT_UAP_TOO_LONG = 7,
 BT_NO_PIO_NUM_MASK = 8,
 BT_NO_PIO_NUM = 9,
 BT_NO_BT_DEVICE =10, //A
 BT_TOO_LENGTH_DEVICES =11, //B (chinglish?)
 BT_NO_INQ_ACCESS_CODE =12, //C
 BT_INQ_ACCESS_CODE_TOO_LONG =13, //D
 BT_INQ_CODE_INVALID =14, //E
 BT_PASS_KEY_LENGTH_0 =15, //F
 BT_PASS_KEY_TOO_LONG =16, //10
 BT_INVALID_MODULE_ROLE =17, //11
 BT_INVALID_BAUD_RATE =18, //12
 BT_INVALID_STOP_BIT =19, //13
 BT_INVALID_PARITY_BIT =20, //14
 BT_AUTH_DEV_NOT_ON_PAIR_LIST =21, //15
 BT_SPP_LIB_NOT_INITIALIZED =22, //16
 BT_SPP_LIB_INIT_REPEATED =23, //17
 BT_INVALID_INQ_MODE =24, //18
 BT_INQ_TIME_TOO_LONG =25, //19
 BT_NO_ADDRESS =26, //1A
 BT_INVALID_SAFE_MODE =27, //1B
 BT_INVALID_ENCRYPTION_MODE =28, //1C
 BT_FAIL =29,  // Generic Failure
 BT_SUCCESS =30
};

enum hc05_connect :uint8_t {
 BT_CONNECTED = 0,
 BT_DISC_SUCCESS = 1,
 BT_DISC_LINK_LOSS = 2,
 BT_DISC_NO_SLC = 3,
 BT_DISC_TIMEOUT = 4,
 BT_DISC_ERROR = 5,
 BT_DISC_UNKNOWN = 6
};

enum hc05_state :uint8_t {
 BT_STATE_UNKNOWN = 0,
 BT_STATE_INITIALIZED = 1,
 BT_STATE_READY = 2,
 BT_STATE_PAIRABLE = 3,
 BT_STATE_PAIRED = 4,
 BT_STATE_INQUIRING = 5,
 BT_STATE_CONNECTING = 6,
 BT_STATE_CONNECTED = 7,
 BT_STATE_DISCONNECTED = 8
};



class HC05 {
 public:
 HC05();
 void setup(const uint8_t power_pin, const uint8_t key_pin, HardwareSerial * serial);
 bool begin(bool try_connect);
 void powerOn();
 void powerOff();
 bool connect();
 void disconnect();
 void setBaud(uint16_t baud_rate) {_baud = baud_rate;}
 bool configure();
 hc05_connect link();
 bool getAddress();
 bool connected() {if ( _connected == BT_CONNECTED ) return true; else return false;}
 hc05_result getResult() {return _bt_result;}
 hc05_state getState() {return _state;}
 hc05_state queryState();
 bool powered() {return _powered;}
 protected:
 hc05_result _sendATcmd(const char * atcmdstr);
 hc05_result _sendATcmd(const char * atcmdstr, uint16_t timeout,bool get_response);
 HardwareSerial * Serial_BT;
 char _buffer[BT_BUFFER_SIZE];
 hc05_connect _connected;
 bool _parseDisconnect(const char * message);
 private:
 hc05_result _bt_result;
 hc05_state _state;
 uint8_t _power_pin;
 uint8_t _key_pin;
 uint32_t _baud;
 char _address[30];
 bool _powered;
};

// Scale status bits:
// powered() Power is on
// connected() We are connected to slave
// areProcessing() We are interested in data from scale.

class BTscale: public HC05{
 public:
 BTscale();
 bool connect();
 void disconnect();
 int16_t getWeight() { return _weight;}
 int16_t getLastWeight() { return _last_weight;}
 float getDecWeight() { return (float)_weight/pow(10,_decimal);}
 int8_t getDecimal() { return _decimal;}
 bool inMotion() { return _motion;}
 void getUnits(char * units) {strncpy(units,_units,7);}
 bool readWeight(); // returns true when full weight has been read.
 uint32_t lastAttempt() { return _last_attempt;}
 void startData();
 void stopData() {_process_data = false;}
 bool getData(); // Get a byte from serial if we are processing data
 bool areProcessing() { return _process_data;}
 private:
 void _clearData();
 bool _negative;
 bool _motion;
 bool _at_command;
 uint32_t _last_attempt;
 int8_t _decimal;
 int16_t _weight;
 int16_t _last_weight;
 char _units[7];
 uint8_t _unit_idx;
 bool _process_data;
};


#endif

.cpp file in another post…

But here’s my console sketch which lets you play with AT commands:

// For Arduino Mega

#define LEDPIN 13
#define BTPWR_M 12
#define BTKEY_M A9
#define BT_STATE_M 0
#define BTSERIAL Serial1

uint8_t index = 0;
bool master_mode = true;
uint8_t read_from = 1;
uint8_t write_to = 1;

char command[50];
bool echo = true;
bool atmode;
char read_char;
bool moreSetup = false;
void setup(){
  Serial.begin(57600);
  Serial.println(F("\tStarting BT test Program compiled "__DATE__ ", " __TIME__ ", " __VERSION__));
  Serial.println(F("'~' toggles console mode"));
  Serial.println(F("'#' toggles echo"));
  Serial.println(F("'!' power cycle"));
  Serial.println(F("'@' run initialize function"));
  pinMode(LEDPIN,OUTPUT);
  pinMode(BTPWR_M,OUTPUT);
  pinMode(BTKEY_M,OUTPUT);
  if ( BT_STATE_M ) pinMode(BT_STATE_M,INPUT);
  digitalWrite(BTPWR_M,LOW);
  digitalWrite(BTKEY_M,HIGH);   atmode = true;//AT mode
  delay(1000);
  BTSERIAL.begin(38400);
  digitalWrite(BTPWR_M,HIGH);
}

void loop(){
        
	while ( Serial.available() ) {
		read_char = (char)Serial.read(); // Needs CRLF in KEY mode.
		switch ( read_char ){
			case ('\r' ):
				if ( echo ) Serial.println();
				BTSERIAL.write("\r\n");
				break;
			case ('\n' ): break;
			case ( '~' ):
				atmode = !atmode;
				digitalWrite(BTKEY_M,atmode); //AT mode
				Serial.print("AT MODE="); Serial.println(atmode);
				delay(1000);
				break;
			case ( '!' ):
				Serial.print("Power cycle"); 
				digitalWrite(BTPWR_M,LOW);
				delay(1000);
				digitalWrite(BTPWR_M,HIGH);
				break;
			case ( '@' ):
				moreSetup = btSetup();
				break;
			case ( '#' ):
				echo = !echo;
				Serial.print("echo="); Serial.println(echo);
				break;
			default:
				BTSERIAL.write(read_char);
				if ( echo) Serial.write(read_char);
				break;
		}
	}
	while ( BTSERIAL.available() ) Serial.write(BTSERIAL.read());
        if ( moreSetup ) moreSetup = btSetup();
}

bool btSetup(){
      static int8_t  step = 0;
      step++;
      switch (step ) {
	case 1: printlnBoth("AT"); break;
	case 2: printlnBoth("AT+ORGL"); break;
        case 3:	printlnBoth("AT+NAME=LimnoT");break;
	case 4: printlnBoth("AT+ROLE=1");break;
	case 5: printlnBoth("AT+CMODE=1");break;
	case 6: printlnBoth("AT+UART=38400,0,0");break;
        default: step = -10;
      }
  if ( step > 0 ) return true;
  else return false;
}

void printlnBoth(char * string){
	BTSERIAL.println(string);
	if ( echo ) Serial.println(string);
}

void getAddress(char * address){
	printlnBoth("AT+ORGL");   
}

Here’s part one of my my cpp file:

#include "LimnoBT.h"

#define BT_DEBUG

#define hex2dec(x) ((x>'9')?10+x-'A':x-'0')

static const char CRLF[] = "\r\n";

HC05::HC05(){
	_baud = 38400;
	_connected = BT_DISC_UNKNOWN;
	_address[0] = 0;
}

void HC05::setup(uint8_t power_pin, uint8_t key_pin, HardwareSerial * serial_bt) {
	_power_pin = power_pin;
	_key_pin = key_pin;
	Serial_BT = serial_bt;
	pinMode(_power_pin,OUTPUT);
	pinMode(_key_pin,OUTPUT);
}

void HC05::powerOn(){
	digitalWrite(_key_pin,LOW);
	digitalWrite(_power_pin,LOW);
	delay(100);
	digitalWrite(_key_pin,HIGH); //AT mode
	delay(100);
	digitalWrite(_power_pin,HIGH);
	_powered = true;
}
void HC05::powerOff(){
	digitalWrite(_key_pin,LOW);
	digitalWrite(_power_pin,LOW);
	_powered = false;
	_connected = BT_DISC_UNKNOWN;
	_state = BT_STATE_DISCONNECTED;
}

bool HC05::configure(){
	// This should only have to be done once
	if ( ( _bt_result = _sendATcmd("CMOD=1")) != BT_SUCCESS ) return false;
	if ( ( _bt_result = _sendATcmd("ROLE=1")) != BT_SUCCESS ) return false;
	if ( ( _bt_result = _sendATcmd("BAUD=38400,0,0")) != BT_SUCCESS ) return false;
	return true;
}


bool HC05::begin(bool try_connect){
	if ( ! powered() ){
		powerOn();
		delay(4000);
	}
	Serial_BT->begin(_baud);
	Serial_BT->setTimeout(2000);
	// Firs a simple AT command
	if ( _sendATcmd(NULL)	!= BT_SUCCESS ) {
#ifdef BT_DEBUG
		Serial.println("AT failed");
#endif
		return false;
	}
	if ( _sendATcmd("INIT")	!= BT_SUCCESS ) {
#ifdef BT_DEBUG
		Serial.println("INIT failed");
#endif
		return false;
	}
	if ( try_connect ) return connect();
	else return true;
}

bool HC05::connect(){
	if ( _address[0] == 0 ) {
		if ( !getAddress() ) {
#ifdef BT_DEBUG
			Serial.println("getAddress failed");
#endif
			return false;
		}
	}
	if ( _address[0] != 0 ){
		// Only if we have address
		if ( link() == BT_CONNECTED ) return true;
#ifdef BT_DEBUG
		else Serial.println("link() failed");
#endif
	}
	return false;
}

void HC05::disconnect(){
	sprintf(_buffer,"AT+DISC%s",CRLF);
#ifdef BT_DEBUG
	Serial.print("disconnect sending:"); Serial.print(_buffer);
#endif
	Serial_BT->print(_buffer);
	delay(500);
	Serial_BT->readBytesUntil('\r',_buffer,BT_BUFFER_SIZE);
	if ( _buffer[0] == 'D' ) {
		// could be DISC:<disc desc>
#ifdef BT_DEBUG
		Serial.print("disconnect read:"); Serial.print(_buffer);
#endif
		_connected = BT_DISC_SUCCESS; // In case we can't parse it?
		_parseDisconnect(_buffer);
	}
	
}

hc05_connect HC05::link(){
	sprintf(_buffer,"LINK=%s",_address);
	hc05_result result = _sendATcmd(_buffer,6000,true);
	if		( result == BT_SUCCESS)	_connected = BT_CONNECTED;
	else if	( result == BT_FAIL)	_connected = BT_DISC_TIMEOUT; // If there's nothing to link to
	else							_connected = BT_DISC_UNKNOWN; 
#ifdef BT_DEBUG
	Serial.print("leaving link() with "); Serial.println(_connected);
#endif
	return _connected;
}

bool HC05::getAddress(){
	Serial_BT->setTimeout(8000);
	sprintf(_buffer,"AT+INQ%s",CRLF);
#ifdef BT_DEBUG
	Serial.print("getAddress sending:"); Serial.print(_buffer);
#endif
	Serial_BT->print(_buffer); _buffer[0] = 0;
	uint8_t bytes_read = Serial_BT->readBytesUntil('\n',_buffer,BT_BUFFER_SIZE);
#ifdef BT_DEBUG
	Serial.print("getAddress got "); Serial.print(bytes_read); Serial.print(" bytes:"); Serial.println(_buffer);
#endif
	if ( bytes_read < 10 ) return false;
	char * addr1 = strtok(_buffer,":,\r"); // Throw away
	addr1 = strtok(NULL,":,\r");
	char * addr2 = strtok(NULL,":,\r");
	char * addr3 = strtok(NULL,":,\r");
	sprintf(_address,"%s,%s,%s",addr1,addr2,addr3);
	while ( Serial_BT->available() ) Serial_BT->read(); // Clear out what remains.
	return true;
}



hc05_result HC05::_sendATcmd(const char * atcmdstr) {
	return _sendATcmd(atcmdstr,2000,true);
}
hc05_result HC05::_sendATcmd(const char * atcmdstr, uint16_t timeout,bool get_response) {
	uint8_t _buf_recvd = 0;
	char _buffer[128];
	_bt_result = BT_FAIL;
#ifdef BT_DEBUG
	Serial.println("Entering _sendATcmd()");
#endif
	strncpy(_buffer,"AT",3);
	if ( atcmdstr[0] ) sprintf(_buffer + 2,"+%s%s",atcmdstr,CRLF);
	else sprintf(_buffer + 2,"%s",CRLF);
#ifdef BT_DEBUG
	Serial.print("\tSending:"); Serial.print(_buffer);
#endif
	Serial_BT->setTimeout(timeout);
	while ( Serial_BT->available() ) Serial_BT->read(); // Clear buffer
	Serial_BT->print(_buffer);
	if ( get_response ) {
		_buf_recvd = Serial_BT->readBytes(_buffer,BT_BUFFER_SIZE);
		_buffer[_buf_recvd] = 0;
		Serial.print("\tGot:"); Serial.print(_buffer); Serial.print("\tOf size "); Serial.println(_buf_recvd);
		if (_buf_recvd >= 2) {
			if ( _buffer[0] == 'O' && _buffer[1] == 'K' ) _bt_result = BT_SUCCESS; // OK
			else if ( _buffer[0] == 'E' ) {
				// Get Error number if _buffer[8] = ')' then 1 digit error code, else 2 digit
				if ( _buf_recvd >= 9 ) {
					uint8_t bt_result = static_cast<hc05_result>( _buffer[8] != ')' )?16*(hex2dec(_buffer[7]))+(hex2dec(_buffer[8])):hex2dec(_buffer[7]);
	#ifdef BT_DEBUG
					Serial.print("\tGot Error code:"); Serial.println(bt_result);
	#endif
					_bt_result = static_cast<hc05_result>(bt_result);
				}
			}
			else if ( _buffer[0] == 'F' ) {
	#ifdef BT_DEBUG
				Serial.println("\tFail");
	#endif
				_bt_result=BT_FAIL;
			}
		}
		// Other cases : consider as valid command
	}
	else _bt_result = BT_SUCCESS; // Nothing received so can't fail
#ifdef BT_DEBUG
	Serial.print("Leaving _sendAtCmd() with _bt_result = "); Serial.println(_bt_result);
#endif
	return _bt_result;  
}


bool HC05::_parseDisconnect(const char * message){
	if ( message[0] == 'D' && message[4] == ':') {
		switch (message[5]) {
			case 'S': _connected = BT_DISC_SUCCESS;		return true;	// +DISC:SUCCESS
			case 'L': _connected = BT_DISC_LINK_LOSS;	return true;	// +DISC:LINK_LOSS
			case 'N': _connected = BT_DISC_NO_SLC;		return true;	// +DISC:NO_SLC
			case 'T': _connected = BT_DISC_TIMEOUT;		return true;	// +DISC:TIMEOUT
			case 'E': _connected = BT_DISC_ERROR;		return true;	// +DISC:ERROR
			default: return false;
		}
	}
	return false;
}




hc05_state HC05::queryState() {
	_bt_result	= BT_FAIL;
	_state		= BT_STATE_UNKNOWN;
	_connected	= BT_DISC_UNKNOWN;
#ifdef BT_DEBUG
	Serial.println("Entering _getState()");
#endif
	_sendATcmd("STATE?",2000,false); // Won't read from Serial_BT
	// We're looking for "+STATE:<param>\r\nOK\r\n
	uint8_t _buf_recvd = Serial_BT->readBytes(_buffer,BT_BUFFER_SIZE);
	if (_buf_recvd > 2 && _buffer[0] == '+') {
#ifdef BT_DEBUG
		uint8_t i = 0;
		while ( i < BT_BUFFER_SIZE - 1 ) {
			if ( _buffer[i] == '\n' ) { _buffer[i] = 0 ; i = BT_BUFFER_SIZE; }
			else i++;
		}
		Serial.print("\tReceived :"); Serial.print(_buffer);
#endif
		if ( _buf_recvd > 12 ) {
			switch (_buffer[7]) {
				case 'R' : _state = BT_STATE_READY;	break;
				case 'D' : _state = BT_STATE_DISCONNECTED;	break;
				case 'I' : _state = (_buffer[9]=='I')?BT_STATE_INITIALIZED:BT_STATE_INQUIRING;	break;
				case 'P' : _state = (_buffer[11]=='A')?BT_STATE_PAIRABLE:BT_STATE_PAIRED;		break;
				case 'C' : 
					if ( _buf_recvd > 16 )	{
						if ( _buffer[14] == 'I') _state = BT_STATE_CONNECTING;
						else {
							BT_STATE_CONNECTED; 
							_connected = BT_CONNECTED;
						}
					}
					else _state	= BT_STATE_UNKNOWN;
					break;
				default : _state = BT_STATE_UNKNOWN;	break;
			}
		}
		_buf_recvd = Serial_BT->readBytes(_buffer,BT_BUFFER_SIZE); // there's still an AT\r\n out there
	} else _bt_result= BT_FAIL;
	// Other cases : consider as valid command
#ifdef BT_DEBUG
	Serial.print("Leaving _getState() with _state = "); Serial.println(_state);
#endif
return _state;
}

Here’s the rest of my cpp file (too big to post all at once.

// -------------------------------------------------------------------------------------

BTscale::BTscale(){
	_clearData();
	_last_attempt = 0;
	_process_data = false;
}

bool BTscale::connect(){
#ifdef BT_DEBUG
	if ( _last_attempt ) Serial.println("Attempting to re-connect");
#endif
	_last_attempt = millis();
	return HC05::connect();
}

void BTscale::disconnect(){
	HC05::disconnect();
	_clearData();	
}
void BTscale::_clearData(){
	_negative			= false;
	_motion				= false;
	_at_command			= false;
	_last_weight		= _weight;
	_weight				= 0;
	_decimal			= 0;
	_unit_idx			= 0;
	_units[_unit_idx]	= 0;	
}

bool BTscale::readWeight() {
	char byte_read;
	//char next_byte;
	bool success = false;
	if ( Serial_BT->available() ) {
		if ( _at_command ) {
			// We got a plus, now need to parse what's left
			delay(500);
			Serial_BT->readBytesUntil('\r',_buffer,BT_BUFFER_SIZE);
			if ( _buffer[0] == 'D' ) {
				// could be DISC:<disc desc>
				_parseDisconnect(_buffer);
				_clearData();
			}
		}
		else {
			byte_read = Serial_BT->read();
			switch (byte_read) {
				case 2:		_clearData();	break; // Start of string STX
				case 13:	break; // do nothing
				case '+':	_at_command = true;	break;// It's an at command.
				case '.':	_decimal++;	break;
				case ' ':	break;
				case 'M':
					_motion = true;		// M
					Serial_BT->read();	// O
					Serial_BT->read();	// T
					break;
				case 10:
					if ( _negative ) _weight *= -1;
					if ( _weight > 0 ) success = true;
					break;
				case '-':
					if ( _units[0] != 'l' ) { _negative = true;	break; }
					// else fall through to units....
				case 'b':	// lb, lb-oz (NOT SUPPORTED)
				case 'g':	// g, kg
				case 'k':	// kg
				case 'l':	// lb,lb-oz(NOT SUPPORTED)
				case 'o':	// oz, lb-oz(NOT SUPPORTED)
				case 'z':	// oz, lb-oz(NOT SUPPORTED)
					_units[_unit_idx] = byte_read;	_unit_idx++;	_units[_unit_idx] = 0;
					break;
				default:
					if ( byte_read >= '0' && byte_read <= '9' ){
						if ( _decimal ) _decimal++;
						_weight = _weight * 10;
						_weight += byte_read - '0';
						sprintf(_buffer,"(%d)",_weight);
					}
					break;
			}
		}
	}
	return success;
}

bool BTscale::getData(){
	if ( areProcessing() ) {
		if ( powered() && connected() ) {
			if ( readWeight() ) {
				if ( ! inMotion() ) return true;
			}
		}
		else if ( powered() ) {
			if ( millis() - lastAttempt() > (15 * 1000)){
				if ( !powered() ) {
					powerOn();
					delay(4000);
				}
				connect();
			}
		}
		
	}
	return false;
}

void BTscale::startData(){
	if ( powered()){
		 _process_data = true;
		 while ( Serial_BT->available() ) Serial_BT->read(); // clear out buffer.
	}
}

RyanN: My objective is to have a 1:1 connection. One scale with one sampling station. My difficulty is that when an operator takes his gear in the field, I don't know which station and which scale they will take. When they start up the station, there will be only one scale to connect to, but I don't know which one.

I'm not sure I understand your application. You have two HC05s. Are they communicating with each other, or with separate devices?

One routinely sends all data continuously, to be picked up by a phone. This may be interrupted to download a file from SD. This is what I normally do. The second HC-05 would send part of the data to another Arduino. This is essentially confectionery and I have not progressed with it.

I'm not really polling. As soon as the two bluetooth modules connect, there is a constant and unending stream of values sent from the slave (HC06) to the master (HC05).

OK. But it seems you are polling to the extent that one bluetooth needs to find another, but I now understand that, once done, that is all that is done and that is probably the hard part. I don't have the expertise to comment on the code but I will bookmark this!

Sounds like the module connecting to the phone should be an HC06 or an HC05 in slave mode AT+ROLE=0. As the master, the phone would be in charge of pairing. The HC06 has a very limited command set, but since my scale doesn't issue any commands, just dumps to the serial port, it can't be too difficult.

Indeed. All my blueteeth are slaves and the HC-05 is slave by default. The only time you need a master is when Arduino has to do the pairing, like you will need to trawl the scales, and I will need to do with the abovementioned. While Cantin talks about using HC-05s, I'm sure an HC-06 will do at the other end. HC-06 is slave only and its command set is more than adequate for that. Name and speed is all you really need.

Rather as an aside, I'm just a little bit suss about HC-06s. While my HC-06 is the bluetooth doing the most work, I could not get it to work with a tablet. They either could see each other but never pair, or pair but not connect. I was inclined to blame the tablet, since deceased, but I believe a couple of others might have had the same problem.

I have never had the problem since, but I wouldn't buy another HC-06.

At the price of an HC-05, the only good reasons for an HC-06 are that thare are more easily configurable, to the point that a one-shot configuration routine can even be painlessly included in Arduino's Setup, but you would have to be a big-time user to really need that.