diff --git a/AcaiaArduinoBLE.cpp b/AcaiaArduinoBLE.cpp index 2bf3112..7cf29e1 100644 --- a/AcaiaArduinoBLE.cpp +++ b/AcaiaArduinoBLE.cpp @@ -1,5 +1,5 @@ /* - AcaiaArduinoBLE.cpp - Library for connecting to + AcaiaArduinoBLE.cpp - Library for connecting to an Acaia Scale using the ArduinoBLE library. Created by Tate Mazer, December 13, 2023. Released into the public domain. @@ -10,51 +10,209 @@ #include "AcaiaArduinoBLE.h" #include -byte IDENTIFY[20] = { 0xef, 0xdd, 0x0b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x9a, 0x6d }; -byte HEARTBEAT[7] = { 0xef, 0xdd, 0x00, 0x02, 0x00, 0x02, 0x00 }; -byte NOTIFICATION_REQUEST[14] = { 0xef, 0xdd, 0x0c, 0x09, 0x00, 0x01, 0x01, 0x02, 0x02, 0x05, 0x03, 0x04, 0x15, 0x06 }; -byte START_TIMER[7] = { 0xef, 0xdd, 0x0d, 0x00, 0x00, 0x00, 0x00 }; -byte STOP_TIMER[7] = { 0xef, 0xdd, 0x0d, 0x00, 0x02, 0x00, 0x02 }; -byte RESET_TIMER[7] = { 0xef, 0xdd, 0x0d, 0x00, 0x01, 0x00, 0x01 }; -byte TARE_ACAIA[6] = { 0xef, 0xdd, 0x04, 0x00, 0x00, 0x00 }; -byte TARE_GENERIC[6] = { 0x03, 0x0a, 0x01, 0x00, 0x00, 0x08 }; -byte START_TIMER_GENERIC[6] = { 0x03, 0x0a, 0x04, 0x00, 0x00, 0x0a }; -byte STOP_TIMER_GENERIC[6] = { 0x03, 0x0a, 0x05, 0x00, 0x00, 0x0d }; -byte RESET_TIMER_GENERIC[6] = { 0x03, 0x0a, 0x06, 0x00, 0x00, 0x0c }; +byte IDENTIFY[20] = {0xef, 0xdd, 0x0b, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x9a, 0x6d}; +byte HEARTBEAT[7] = {0xef, 0xdd, 0x00, 0x02, 0x00, 0x02, 0x00}; +byte NOTIFICATION_REQUEST[14] = {0xef, 0xdd, 0x0c, 0x09, 0x00, 0x01, 0x01, 0x02, 0x02, 0x05, 0x03, 0x04, 0x15, 0x06}; +byte START_TIMER[7] = {0xef, 0xdd, 0x0d, 0x00, 0x00, 0x00, 0x00}; +byte STOP_TIMER[7] = {0xef, 0xdd, 0x0d, 0x00, 0x02, 0x00, 0x02}; +byte RESET_TIMER[7] = {0xef, 0xdd, 0x0d, 0x00, 0x01, 0x00, 0x01}; +byte TARE_ACAIA[6] = {0xef, 0xdd, 0x04, 0x00, 0x00, 0x00}; +byte TARE_GENERIC[6] = {0x03, 0x0a, 0x01, 0x00, 0x00, 0x08}; +byte START_TIMER_GENERIC[6] = {0x03, 0x0a, 0x04, 0x00, 0x00, 0x0a}; +byte STOP_TIMER_GENERIC[6] = {0x03, 0x0a, 0x05, 0x00, 0x00, 0x0d}; +byte RESET_TIMER_GENERIC[6] = {0x03, 0x0a, 0x06, 0x00, 0x00, 0x0c}; /* Generic commands from https://github.com/graphefruit/Beanconqueror/blob/master/src/classes/devices/felicita/constants.ts */ -AcaiaArduinoBLE::AcaiaArduinoBLE(bool debug){ +AcaiaArduinoBLE::AcaiaArduinoBLE(bool debug) +{ _debug = debug; _currentWeight = 0; _connected = false; _packetPeriod = 0; + _scanActive = false; + _scanStart = 0; } -bool AcaiaArduinoBLE::init(String mac){ +bool AcaiaArduinoBLE::initNonBlocking(String mac) +{ Serial.print("AcaiaArduinoBLE Library v"); Serial.print(LIBRARY_VERSION); Serial.println(" reinitializing..."); + if (!_scanActive) + { + // Start or restart a scan when we don't have one running + BLE.scan(); + _scanActive = true; + _scanStart = millis(); + } + + BLEDevice peripheral = BLE.available(); + + if (_debug && peripheral) + { + // discovered a peripheral, print out address, local name, and advertised service + Serial.print("Found "); + Serial.print(peripheral.address()); + Serial.print(" '"); + Serial.print(peripheral.localName()); + Serial.print("' "); + Serial.print(peripheral.advertisedServiceUuid()); + Serial.println(); + } + + bool nameMatches = peripheral && isScaleName(peripheral.localName()); + bool macMatches = peripheral && mac.length() && (peripheral.address() == mac); + bool accept = peripheral && (mac.length() ? macMatches : nameMatches); + + if (accept) + { + BLE.stopScan(); + _scanActive = false; + + Serial.println("Connecting ..."); + if (peripheral.connect()) + { + Serial.println("Connected"); + } + else + { + Serial.println("Failed to connect!"); + return false; + } + + Serial.println("Discovering attributes ..."); + if (peripheral.discoverAttributes()) + { + Serial.println("Attributes discovered"); + ; + } + else + { + Serial.println("Attribute discovery failed!"); + peripheral.disconnect(); + return false; + } + + if (_debug) + { + // read and print device name of peripheral + Serial.println(); + Serial.print("Device name: "); + Serial.println(peripheral.deviceName()); + Serial.print("Appearance: 0x"); + Serial.println(peripheral.appearance(), HEX); + Serial.println(); + + // loop the services of the peripheral and explore each + for (int i = 0; i < peripheral.serviceCount(); i++) + { + BLEService service = peripheral.service(i); + exploreService(service); + } + } + + // Determine type of scale + if (peripheral.characteristic(READ_CHAR_OLD_VERSION).canSubscribe()) + { + Serial.println("Old version Acaia Detected"); + _type = OLD; + _write = peripheral.characteristic(WRITE_CHAR_OLD_VERSION); + _read = peripheral.characteristic(READ_CHAR_OLD_VERSION); + } + else if (peripheral.characteristic(READ_CHAR_NEW_VERSION).canSubscribe()) + { + Serial.println("New version Acaia Detected"); + _type = NEW; + _write = peripheral.characteristic(WRITE_CHAR_NEW_VERSION); + _read = peripheral.characteristic(READ_CHAR_NEW_VERSION); + } + else if (peripheral.characteristic(READ_CHAR_GENERIC).canSubscribe()) + { + Serial.println("Generic Scale Detected"); + _type = GENERIC; + _write = peripheral.characteristic(WRITE_CHAR_GENERIC); + _read = peripheral.characteristic(READ_CHAR_GENERIC); + } + else + { + Serial.println("unable to determine scale type"); + return false; + } + + if (!_read.canSubscribe()) + { + Serial.println("unable to subscribe to READ"); + return false; + } + else if (!_read.subscribe()) + { + Serial.println("subscription failed"); + return false; + } + else + { + Serial.println("subscribed!"); + } + + if (_write.writeValue(IDENTIFY, 20)) + { + Serial.println("identify write successful"); + } + else + { + Serial.println("identify write failed"); + return false; + } + if (_write.writeValue(NOTIFICATION_REQUEST, 14)) + { + Serial.println("notification request write successful"); + } + else + { + Serial.println("notification request write failed"); + return false; + } + _connected = true; + _packetPeriod = 0; + _lastPacket = 0; + return true; + } + + return false; +} + +bool AcaiaArduinoBLE::init(String mac, unsigned long timeoutMs) +{ + + Serial.print("AcaiaArduinoBLE Library v"); + Serial.print(LIBRARY_VERSION); + Serial.println(" reinitializing (blocking)..."); + unsigned long start = millis(); _lastPacket = 0; - if (mac == ""){ + if (mac == "") + { BLE.scan(); - }else if (!BLE.scanForAddress(mac)){ + } + else if (!BLE.scanForAddress(mac)) + { Serial.print("Failed to find "); Serial.println(mac); return false; } - - do{ + + do + { BLEDevice peripheral = BLE.available(); - if(_debug && peripheral){ - // discovered a peripheral, print out address, local name, and advertised service + if (_debug && peripheral) + { Serial.print("Found "); Serial.print(peripheral.address()); Serial.print(" '"); @@ -64,28 +222,36 @@ bool AcaiaArduinoBLE::init(String mac){ Serial.println(); } - if (peripheral && isScaleName(peripheral.localName())) { + if (peripheral && isScaleName(peripheral.localName())) + { BLE.stopScan(); Serial.println("Connecting ..."); - if (peripheral.connect()) { + if (peripheral.connect()) + { Serial.println("Connected"); - } else { + } + else + { Serial.println("Failed to connect!"); return false; } Serial.println("Discovering attributes ..."); - if (peripheral.discoverAttributes()) { - Serial.println("Attributes discovered");; - } else { + if (peripheral.discoverAttributes()) + { + Serial.println("Attributes discovered"); + ; + } + else + { Serial.println("Attribute discovery failed!"); peripheral.disconnect(); return false; } - if(_debug){ - // read and print device name of peripheral + if (_debug) + { Serial.println(); Serial.print("Device name: "); Serial.println(peripheral.deviceName()); @@ -93,161 +259,212 @@ bool AcaiaArduinoBLE::init(String mac){ Serial.println(peripheral.appearance(), HEX); Serial.println(); - // loop the services of the peripheral and explore each - for (int i = 0; i < peripheral.serviceCount(); i++) { + for (int i = 0; i < peripheral.serviceCount(); i++) + { BLEService service = peripheral.service(i); exploreService(service); } } - // Determine type of scale - if(peripheral.characteristic(READ_CHAR_OLD_VERSION).canSubscribe()){ + if (peripheral.characteristic(READ_CHAR_OLD_VERSION).canSubscribe()) + { Serial.println("Old version Acaia Detected"); - _type = OLD; - _write = peripheral.characteristic(WRITE_CHAR_OLD_VERSION); - _read = peripheral.characteristic(READ_CHAR_OLD_VERSION); - }else if(peripheral.characteristic(READ_CHAR_NEW_VERSION).canSubscribe()){ + _type = OLD; + _write = peripheral.characteristic(WRITE_CHAR_OLD_VERSION); + _read = peripheral.characteristic(READ_CHAR_OLD_VERSION); + } + else if (peripheral.characteristic(READ_CHAR_NEW_VERSION).canSubscribe()) + { Serial.println("New version Acaia Detected"); - _type = NEW; - _write = peripheral.characteristic(WRITE_CHAR_NEW_VERSION); - _read = peripheral.characteristic(READ_CHAR_NEW_VERSION); - } else if(peripheral.characteristic(READ_CHAR_GENERIC).canSubscribe()){ + _type = NEW; + _write = peripheral.characteristic(WRITE_CHAR_NEW_VERSION); + _read = peripheral.characteristic(READ_CHAR_NEW_VERSION); + } + else if (peripheral.characteristic(READ_CHAR_GENERIC).canSubscribe()) + { Serial.println("Generic Scale Detected"); - _type = GENERIC; - _write = peripheral.characteristic(WRITE_CHAR_GENERIC); - _read = peripheral.characteristic(READ_CHAR_GENERIC); + _type = GENERIC; + _write = peripheral.characteristic(WRITE_CHAR_GENERIC); + _read = peripheral.characteristic(READ_CHAR_GENERIC); } - else{ + else + { Serial.println("unable to determine scale type"); return false; } - if(!_read.canSubscribe()){ + if (!_read.canSubscribe()) + { Serial.println("unable to subscribe to READ"); return false; - }else if(!_read.subscribe()){ + } + else if (!_read.subscribe()) + { Serial.println("subscription failed"); return false; - }else { + } + else + { Serial.println("subscribed!"); } - - if(_write.writeValue(IDENTIFY, 20)){ + + if (_write.writeValue(IDENTIFY, 20)) + { Serial.println("identify write successful"); - }else{ + } + else + { Serial.println("identify write failed"); - return false; + return false; } - if(_write.writeValue(NOTIFICATION_REQUEST,14)){ + if (_write.writeValue(NOTIFICATION_REQUEST, 14)) + { Serial.println("notification request write successful"); - }else{ + } + else + { Serial.println("notification request write failed"); - return false; + return false; } _connected = true; _packetPeriod = 0; + _lastPacket = 0; return true; } - }while(millis() - start < 10000); + } while (millis() - start < timeoutMs); + + BLE.stopScan(); Serial.println("failed to find scale"); - return false; + return false; } -bool AcaiaArduinoBLE::tare(){ - if(_write.writeValue((_type == GENERIC ? TARE_GENERIC : TARE_ACAIA), 6)){ - Serial.println("tare write successful"); - return true; - }else{ +bool AcaiaArduinoBLE::tare() +{ + if (_write.writeValue((_type == GENERIC ? TARE_GENERIC : TARE_ACAIA), 6)) + { + Serial.println("tare write successful"); + return true; + } + else + { _connected = false; Serial.println("tare write failed"); return false; } } -bool AcaiaArduinoBLE::startTimer(){ - if(_write.writeValue((_type == GENERIC ? START_TIMER_GENERIC : START_TIMER), - (_type == GENERIC ? 6 : 7))){ - Serial.println("start timer write successful"); +bool AcaiaArduinoBLE::startTimer() +{ + if (_write.writeValue((_type == GENERIC ? START_TIMER_GENERIC : START_TIMER), + (_type == GENERIC ? 6 : 7))) + { + Serial.println("start timer write successful"); return true; - }else{ + } + else + { _connected = false; Serial.println("start timer write failed"); return false; } } -bool AcaiaArduinoBLE::stopTimer(){ - if(_write.writeValue((_type == GENERIC ? STOP_TIMER_GENERIC : STOP_TIMER), - (_type == GENERIC ? 6 : 7 ))){ +bool AcaiaArduinoBLE::stopTimer() +{ + if (_write.writeValue((_type == GENERIC ? STOP_TIMER_GENERIC : STOP_TIMER), + (_type == GENERIC ? 6 : 7))) + { Serial.println("stop timer write successful"); return true; - }else{ + } + else + { _connected = false; Serial.println("stop timer write failed"); return false; } } -bool AcaiaArduinoBLE::resetTimer(){ - if(_write.writeValue((_type == GENERIC ? RESET_TIMER_GENERIC : RESET_TIMER), - (_type == GENERIC ? 6 : 7 ))){ +bool AcaiaArduinoBLE::resetTimer() +{ + if (_write.writeValue((_type == GENERIC ? RESET_TIMER_GENERIC : RESET_TIMER), + (_type == GENERIC ? 6 : 7))) + { Serial.println("reset timer write successful"); return true; - }else{ + } + else + { _connected = false; Serial.println("reset timer write failed"); return false; } } -bool AcaiaArduinoBLE::heartbeat(){ - if(_write.writeValue(HEARTBEAT, 7)){ +bool AcaiaArduinoBLE::heartbeat() +{ + if (_write.writeValue(HEARTBEAT, 7)) + { _lastHeartBeat = millis(); return true; - }else{ + } + else + { _connected = false; return false; } } -float AcaiaArduinoBLE::getWeight(){ +float AcaiaArduinoBLE::getWeight() +{ return _currentWeight; } -bool AcaiaArduinoBLE::heartbeatRequired(){ - if(_type == OLD || _type == NEW){ +bool AcaiaArduinoBLE::heartbeatRequired() +{ + if (_type == OLD || _type == NEW) + { return (millis() - _lastHeartBeat) > HEARTBEAT_PERIOD_MS; - }else{ + } + else + { return 0; } } -bool AcaiaArduinoBLE::isConnected(){ +bool AcaiaArduinoBLE::isConnected() +{ return _connected; } -bool AcaiaArduinoBLE::newWeightAvailable(){ +bool AcaiaArduinoBLE::newWeightAvailable() +{ bool newWeightPacket = false; - //check how long its been since we last got a response - if(_lastPacket && millis()-_lastPacket > MAX_PACKET_PERIOD_MS){ + // check how long its been since we last got a response + if (_lastPacket && millis() - _lastPacket > MAX_PACKET_PERIOD_MS) + { Serial.println("timeout!"); - //reset connection + // reset connection _connected = false; BLE.disconnect(); return false; - }else if(_read.valueUpdated()){ - byte input[] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; + } + else if (_read.valueUpdated()) + { + byte input[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int l = _read.valueLength(); // Get packet - if(10 >= l || //10 byte packets for pre-2021 lunar - (13 >= l && OLD != _type) || //13 byte packets for pyxis and older lunar 2021 fw - (14 == l && OLD == _type) || //14 byte packets for lunar 2021 AL008 - (17 == l && NEW == _type) || //17 byte packets for newer lunar 2021 fw - (20 == l && GENERIC == _type) //18 byte packets for generic scales - ){ + if (10 >= l || // 10 byte packets for pre-2021 lunar + (13 >= l && OLD != _type) || // 13 byte packets for pyxis and older lunar 2021 fw + (14 == l && OLD == _type) || // 14 byte packets for lunar 2021 AL008 + (17 == l && NEW == _type) || // 17 byte packets for newer lunar 2021 fw + (20 == l && GENERIC == _type) // 18 byte packets for generic scales + ) + { _read.readValue(input, (l > 13) ? 13 : l); // readValue() seems to crash whenever l > weight packet (10, 13 or 18) - if(_debug){ + if (_debug) + { Serial.print(l); Serial.print(": 0x"); @@ -259,123 +476,131 @@ bool AcaiaArduinoBLE::newWeightAvailable(){ // Parse New style data packet if (NEW == _type && (13 == l || 17 == l) && input[4] == 0x05) { - //Grab weight bytes (5 and 6) - // apply scaling based on the unit byte (9) - // get sign byte (10) - _currentWeight = (((input[6] & 0xff) << 8) + (input[5] & 0xff)) - / pow(10,input[9]) - * ((input[10] & 0x02) ? -1 : 1); + // Grab weight bytes (5 and 6) + // apply scaling based on the unit byte (9) + // get sign byte (10) + _currentWeight = (((input[6] & 0xff) << 8) + (input[5] & 0xff)) / pow(10, input[9]) * ((input[10] & 0x02) ? -1 : 1); newWeightPacket = true; - // Parse old style data packet - }else if( OLD == _type && (l == 10 || l == 14)){ - //Grab weight bytes (2 and 3), - // apply scaling based on the unit byte (6) - // get sign byte (7) - _currentWeight = (((input[3] & 0xff) << 8) + (input[2] & 0xff)) - / pow(10, input[6]) - * ((input[7] & 0x02) ? -1 : 1); + // Parse old style data packet + } + else if (OLD == _type && (l == 10 || l == 14)) + { + // Grab weight bytes (2 and 3), + // apply scaling based on the unit byte (6) + // get sign byte (7) + _currentWeight = (((input[3] & 0xff) << 8) + (input[2] & 0xff)) / pow(10, input[6]) * ((input[7] & 0x02) ? -1 : 1); newWeightPacket = true; + } + else if (GENERIC == _type && l == 20) + { + // Grab weight bytes (3-8), + // get sign byte (2) + _currentWeight = ((input[7] << 16) | (input[8] << 8) | input[9]); - }else if( GENERIC == _type && l == 20){ - //Grab weight bytes (3-8), - // get sign byte (2) - _currentWeight = (( input[7] << 16) | (input[8] << 8) | input[9]); - - if (input[6] == 45) { // Check if the value is negative - _currentWeight = -_currentWeight; - } + if (input[6] == 45) + { // Check if the value is negative + _currentWeight = -_currentWeight; + } _currentWeight = _currentWeight / 100; newWeightPacket = true; } - if(newWeightPacket){ - if(_lastPacket){ + if (newWeightPacket) + { + if (_lastPacket) + { _packetPeriod = millis() - _lastPacket; } _lastPacket = millis(); } return newWeightPacket; } - else{ + else + { return false; } } -bool AcaiaArduinoBLE::isScaleName(String name){ - String nameShort = name.substring(0,5); - - return nameShort == "CINCO" - || nameShort == "ACAIA" - || nameShort == "PYXIS" - || nameShort == "LUNAR" - || nameShort == "PEARL" - || nameShort == "PROCH" - || nameShort == "BOOKO"; +bool AcaiaArduinoBLE::isScaleName(String name) +{ + String nameShort = name.substring(0, 5); + + return nameShort == "CINCO" || nameShort == "ACAIA" || nameShort == "PYXIS" || nameShort == "LUNAR" || nameShort == "PEARL" || nameShort == "PROCH" || nameShort == "BOOKO"; } -void AcaiaArduinoBLE::exploreService(BLEService service) { - // print the UUID of the service - Serial.print("Service "); - Serial.println(service.uuid()); +void AcaiaArduinoBLE::exploreService(BLEService service) +{ + // print the UUID of the service + Serial.print("Service "); + Serial.println(service.uuid()); - // loop the characteristics of the service and explore each - for (int i = 0; i < service.characteristicCount(); i++) { - BLECharacteristic characteristic = service.characteristic(i); + // loop the characteristics of the service and explore each + for (int i = 0; i < service.characteristicCount(); i++) + { + BLECharacteristic characteristic = service.characteristic(i); - exploreCharacteristic(characteristic); - } + exploreCharacteristic(characteristic); + } } -void AcaiaArduinoBLE::exploreCharacteristic(BLECharacteristic characteristic) { - // print the UUID and properties of the characteristic - Serial.print("\tCharacteristic "); - Serial.print(characteristic.uuid()); - Serial.print(", properties 0x"); - Serial.print(characteristic.properties(), HEX); - - // check if the characteristic is readable - if (characteristic.canRead()) { - // read the characteristic value - characteristic.read(); - - if (characteristic.valueLength() > 0) { - // print out the value of the characteristic - Serial.print(", value 0x"); - printData(characteristic.value(), characteristic.valueLength()); +void AcaiaArduinoBLE::exploreCharacteristic(BLECharacteristic characteristic) +{ + // print the UUID and properties of the characteristic + Serial.print("\tCharacteristic "); + Serial.print(characteristic.uuid()); + Serial.print(", properties 0x"); + Serial.print(characteristic.properties(), HEX); + + // check if the characteristic is readable + if (characteristic.canRead()) + { + // read the characteristic value + characteristic.read(); + + if (characteristic.valueLength() > 0) + { + // print out the value of the characteristic + Serial.print(", value 0x"); + printData(characteristic.value(), characteristic.valueLength()); + } } - } - Serial.println(); + Serial.println(); - // loop the descriptors of the characteristic and explore each - for (int i = 0; i < characteristic.descriptorCount(); i++) { - BLEDescriptor descriptor = characteristic.descriptor(i); + // loop the descriptors of the characteristic and explore each + for (int i = 0; i < characteristic.descriptorCount(); i++) + { + BLEDescriptor descriptor = characteristic.descriptor(i); - exploreDescriptor(descriptor); - } + exploreDescriptor(descriptor); + } } -void AcaiaArduinoBLE::exploreDescriptor(BLEDescriptor descriptor) { - // print the UUID of the descriptor - Serial.print("\t\tDescriptor "); - Serial.print(descriptor.uuid()); +void AcaiaArduinoBLE::exploreDescriptor(BLEDescriptor descriptor) +{ + // print the UUID of the descriptor + Serial.print("\t\tDescriptor "); + Serial.print(descriptor.uuid()); - // read the descriptor value - descriptor.read(); + // read the descriptor value + descriptor.read(); - // print out the value of the descriptor - Serial.print(", value 0x"); - printData(descriptor.value(), descriptor.valueLength()); + // print out the value of the descriptor + Serial.print(", value 0x"); + printData(descriptor.value(), descriptor.valueLength()); - Serial.println(); + Serial.println(); } -void AcaiaArduinoBLE::printData(const unsigned char data[], int length) { - for (int i = 0; i < length; i++) { - unsigned char b = data[i]; +void AcaiaArduinoBLE::printData(const unsigned char data[], int length) +{ + for (int i = 0; i < length; i++) + { + unsigned char b = data[i]; - if (b < 16) { - Serial.print("0"); - } + if (b < 16) + { + Serial.print("0"); + } - Serial.print(b, HEX); - } + Serial.print(b, HEX); + } } diff --git a/AcaiaArduinoBLE.h b/AcaiaArduinoBLE.h index c0e9b5d..de7215e 100644 --- a/AcaiaArduinoBLE.h +++ b/AcaiaArduinoBLE.h @@ -1,10 +1,10 @@ /* - AcaiaArduinoBLE.h - Library for connecting to + AcaiaArduinoBLE.h - Library for connecting to an Acaia Scale using the ArduinoBLE library. Created by Tate Mazer, December 13, 2023. Released into the public domain. - Pio Baettig: Adding Felicita Arc support + Pio Baettig: Adding Felicita Arc support Known Bugs: * Only supports Grams @@ -12,56 +12,64 @@ #ifndef AcaiaArduinoBLE_h #define AcaiaArduinoBLE_h -#define LIBRARY_VERSION "3.2.0" +#define LIBRARY_VERSION "3.2.0" #define WRITE_CHAR_OLD_VERSION "2a80" -#define READ_CHAR_OLD_VERSION "2a80" +#define READ_CHAR_OLD_VERSION "2a80" #define WRITE_CHAR_NEW_VERSION "49535343-8841-43f4-a8d4-ecbe34729bb3" -#define READ_CHAR_NEW_VERSION "49535343-1e4d-4bd9-ba61-23c647249616" -#define WRITE_CHAR_GENERIC "ff12" -#define READ_CHAR_GENERIC "ff11" -#define HEARTBEAT_PERIOD_MS 2750 -#define MAX_PACKET_PERIOD_MS 5000 +#define READ_CHAR_NEW_VERSION "49535343-1e4d-4bd9-ba61-23c647249616" +#define WRITE_CHAR_GENERIC "ff12" +#define READ_CHAR_GENERIC "ff11" +#define HEARTBEAT_PERIOD_MS 2750 +#define MAX_PACKET_PERIOD_MS 5000 #include "Arduino.h" #include -enum scale_type{ +enum scale_type +{ OLD, // Lunar (pre-2021) NEW, // Lunar (2021), Pyxis GENERIC // Felicita Arc, etc }; -class AcaiaArduinoBLE{ - public: - AcaiaArduinoBLE(bool debug); - bool init(String = ""); - bool tare(); - bool startTimer(); - bool stopTimer(); - bool resetTimer(); - bool heartbeat(); - float getWeight(); - bool heartbeatRequired(); - bool isConnected(); - bool newWeightAvailable(); - private: - bool isScaleName(String); +class AcaiaArduinoBLE +{ +public: + AcaiaArduinoBLE(bool debug); + // Blocking: scans up to timeoutMs (default 10s) before giving up + bool init(String mac = "", unsigned long timeoutMs = 10000); + // Non-blocking: starts/continues scanning and returns immediately; call each loop + bool initNonBlocking(String mac = ""); + bool tare(); + bool startTimer(); + bool stopTimer(); + bool resetTimer(); + bool heartbeat(); + float getWeight(); + bool heartbeatRequired(); + bool isConnected(); + bool newWeightAvailable(); - //debug functions - void exploreService(BLEService service); - void exploreCharacteristic(BLECharacteristic characteristic); - void exploreDescriptor(BLEDescriptor descriptor); - void printData(const unsigned char data[], int length); +private: + bool isScaleName(String); + bool _scanActive; + unsigned long _scanStart; - float _currentWeight; - BLECharacteristic _write; - BLECharacteristic _read; - long _lastHeartBeat; - bool _connected; - scale_type _type; - bool _debug; - long _packetPeriod; - long _lastPacket; + // debug functions + void exploreService(BLEService service); + void exploreCharacteristic(BLECharacteristic characteristic); + void exploreDescriptor(BLEDescriptor descriptor); + void printData(const unsigned char data[], int length); + + float _currentWeight; + BLECharacteristic _write; + BLECharacteristic _read; + long _lastHeartBeat; + bool _connected; + scale_type _type; + bool _debug; + long _packetPeriod; + long _lastPacket; }; #endif