-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 195972a
Showing
6 changed files
with
490 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Aranet4 ESP32 client | ||
|
||
This library allows you to read data from Aranet4 devices using Bluetooth. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* This simple example demonstrates how to connect to Aranet4 | ||
* device and read sensor data | ||
* | ||
* Name: BasicRead.ino | ||
* Created: 2021-04-18 | ||
* Author: Anrijs Jargans <anrijs@anrijs.lv> | ||
* Url: https://github.com/Anrijs/Aranet4-ESP32 | ||
*/ | ||
|
||
#include "Aranet4.h" | ||
|
||
// Create custom callback to allow PIN code input. | ||
// In this example, when PIN is requested, you must enter it in serial console. | ||
class MyAranet4Callbacks: public Aranet4Callbacks { | ||
uint32_t onPinRequested() { | ||
Serial.println("PIN Requested. Enter PIN in serial console."); | ||
while(Serial.available() == 0) | ||
vTaskDelay(500 / portTICK_PERIOD_MS); | ||
|
||
return Serial.readString().toInt(); | ||
} | ||
|
||
void onConnected() { | ||
Serial.println("Device conencted"); | ||
} | ||
|
||
void onFailed(uint8_t code) { | ||
Serial.print("Connection failed: "); | ||
switch (code) { | ||
case AR4_ERR_NOT_CONNECTED: Serial.println("not connected"); break; | ||
case AR4_ERR_UNAUTHORIZED: Serial.println("unauthorized"); break; | ||
default: Serial.println("unknown)"); break; | ||
} | ||
} | ||
|
||
void onDisconnected() { | ||
Serial.println("Aranet4 disconencted"); | ||
} | ||
}; | ||
|
||
void setup() { | ||
Serial.begin(115200); | ||
Serial.println("Init"); | ||
|
||
// Address can be string or byte array | ||
// uint8_t addr[] = {0xc00 0x01, 0x02, 0x03, 0x04, 0x05 }; | ||
String addr = "00:01:02:03:04:05"; // Put your Aranet4 MAC address here | ||
|
||
Aranet4 ar4; | ||
ar4.init(new MyAranet4Callbacks()); | ||
|
||
Serial.println("Connecting..."); | ||
if (ar4.connect(addr) == AR4_OK) { | ||
AranetData data = ar4.getCurrentReadings(); | ||
|
||
if (ar4.getStatus() == AR4_OK) { | ||
Serial.println("Aranet4 read OK"); | ||
Serial.printf("CO2: %i ppm\n", data.co2); | ||
Serial.printf("Temperature: %.2f C\n", data.temperature / 20.0); | ||
Serial.printf("Pressure: %.1f C\n", data.pressure / 10.0); | ||
Serial.printf("Humidity: %i %%\n", data.humidity); | ||
Serial.printf("Battery: %i %%\n", data.battery); | ||
Serial.printf("Interval: %i s\n", data.interval); | ||
Serial.printf("Ago: %i s\n", data.ago); | ||
} else { | ||
Serial.printf("Aranet4 read failed: (%i)\n", ar4.getStatus()); | ||
} | ||
} | ||
|
||
ar4.disconnect(); | ||
} | ||
|
||
void loop() { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
####################################### | ||
# Syntax Coloring Map For Aranet4 | ||
####################################### | ||
|
||
####################################### | ||
# Datatypes (KEYWORD1) | ||
####################################### | ||
|
||
Aranet4 KEYWORD1 | ||
|
||
####################################### | ||
# Methods and Functions (KEYWORD2) | ||
####################################### | ||
|
||
readData KEYWORD2 | ||
isPaired KEYWORD2 | ||
|
||
####################################### | ||
# Instances (KEYWORD2) | ||
####################################### | ||
|
||
co2 KEYWORD2 | ||
temperature KEYWORD2 | ||
pressure KEYWORD2 | ||
humidity KEYWORD2 | ||
battery KEYWORD2 | ||
interval KEYWORD2 | ||
ago KEYWORD2 | ||
|
||
####################################### | ||
# Constants (LITERAL1) | ||
####################################### | ||
|
||
AR4_OK LITERAL1 | ||
AR4_FAIL LITERAL1 | ||
AR4_ERR_NO_GATT_SERVICE LITERAL1 | ||
AR4_ERR_NO_GATT_CHAR LITERAL1 | ||
AR4_ERR_NO_CLIENT LITERAL1 | ||
AR4_ERR_NOT_CONNECTED LITERAL1 | ||
AR4_ERR_UNAUTHORIZED LITERAL1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name=Aranet4 | ||
version=1.0.0 | ||
author=Anrijs Jargans | ||
maintainer=Anrijs Jargans <anrijs@anrijs.lv> | ||
sentence= Aranet4 communication library for ESP32 | ||
paragraph=Allows to pair with Aranet4 device and read measurements | ||
category=Communication | ||
url=https://github.com/Anrijs/Aranet4-ESP32 | ||
architectures=esp32 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
/* | ||
* Name: Aranet4.cpp | ||
* Created: 2021-04-17 | ||
* Author: Anrijs Jargans <anrijs@anrijs.lv> | ||
* Url: https://github.com/Anrijs/Aranet4-ESP32 | ||
*/ | ||
|
||
#include "aranet4.h" | ||
#include "Arduino.h" | ||
|
||
/** | ||
* @brief Initialize ESP32 bluetooth device and security profile | ||
* @param [in] cllbacks Pointer to Aranet4Callbacks class callback | ||
*/ | ||
void Aranet4::init(Aranet4Callbacks* callbacks) { | ||
aranetCallbacks = callbacks; | ||
|
||
// Set up bluetooth device and security | ||
BLEDevice::init(""); | ||
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); | ||
BLEDevice::setSecurityCallbacks(aranetCallbacks); | ||
|
||
BLESecurity *pSecurity = new BLESecurity(); | ||
pSecurity->setKeySize(); | ||
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND); | ||
pSecurity->setCapability(ESP_IO_CAP_IN); | ||
pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); | ||
} | ||
|
||
/** | ||
* @brief Check if device is paired | ||
* @param [in] addr Address of bluetooth device | ||
* @return True if device is paired | ||
*/ | ||
bool Aranet4::isPaired(esp_bd_addr_t addr) { | ||
int count = esp_ble_get_bond_device_num(); | ||
|
||
esp_ble_bond_dev_t* devList = (esp_ble_bond_dev_t*) malloc(count * sizeof(esp_ble_bond_dev_t)); | ||
esp_err_t status = esp_ble_get_bond_device_list(&count, devList); | ||
|
||
if (status != ESP_OK) { | ||
Serial.println("Aranet4: Failed to get bonded device list"); | ||
return false; | ||
} | ||
|
||
for (int devId=0; devId<count; devId++) { | ||
esp_ble_bond_dev_t paired = devList[devId]; | ||
if (memcmp(addr, paired.bd_addr, ESP_BD_ADDR_LEN) == 0) return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @brief Connect to Aranet4 device | ||
* @param [in] addr Address of bluetooth device | ||
* @return Connection status code (AR4_CONN_*) | ||
*/ | ||
ar4_err_t Aranet4::connect(esp_bd_addr_t addr) { | ||
pClient = BLEDevice::createClient(); | ||
|
||
bool stat = pClient->connect(addr, BLE_ADDR_TYPE_RANDOM); | ||
|
||
if (!stat) { | ||
aranetCallbacks->onFailed(AR4_ERR_NOT_CONNECTED); | ||
return AR4_ERR_NOT_CONNECTED; | ||
} | ||
|
||
// Wait for auth callback | ||
while(!aranetCallbacks->isConnected()) { | ||
vTaskDelay(100 / portTICK_PERIOD_MS); | ||
} | ||
|
||
if (aranetCallbacks->isAuthenticated()) { | ||
aranetCallbacks->onConnected(); | ||
return AR4_OK; | ||
} | ||
|
||
aranetCallbacks->onFailed(AR4_ERR_UNAUTHORIZED); | ||
return AR4_ERR_UNAUTHORIZED; | ||
} | ||
|
||
/** | ||
* @brief Connect to Aranet4 device | ||
* @param [in] addr Address of bluetooth device | ||
* @return Connection status code (AR4_CONN_*) | ||
*/ | ||
ar4_err_t Aranet4::connect(String addr) { | ||
BLEAddress bleAddr = BLEAddress(addr.c_str()); | ||
esp_bd_addr_t* native = bleAddr.getNative(); | ||
|
||
return connect(*bleAddr.getNative()); | ||
} | ||
|
||
/** | ||
* @brief Disconnects from bluetooth device | ||
*/ | ||
void Aranet4::disconnect() { | ||
if (pClient != nullptr) { | ||
// Without delay, there could be crash | ||
vTaskDelay(500 / portTICK_PERIOD_MS); | ||
pClient->disconnect(); | ||
} | ||
|
||
aranetCallbacks->onDisconnected(); | ||
} | ||
|
||
/** | ||
* @brief Current readings from Aranet4 | ||
*/ | ||
AranetData Aranet4::getCurrentReadings() { | ||
AranetData data; | ||
uint16_t len = sizeof(AranetData); | ||
status = getValue(UUID_Aranet4, UUID_Aranet4_CurrentReadingsDet, (uint8_t*) &data, &len); | ||
|
||
return data; | ||
} | ||
|
||
/** | ||
* @brief Seconds since last Aranet4 measurement | ||
*/ | ||
uint16_t Aranet4::getSecondsSinceUpdate() { | ||
return getU16Value(UUID_Aranet4, UUID_Aranet4_SecondsSinceUpdate); | ||
} | ||
|
||
/** | ||
* @brief Total readings stored in Aranet4 memory | ||
*/ | ||
uint16_t Aranet4::getTotalReadings() { | ||
return getU16Value(UUID_Aranet4, UUID_Aranet4_TotalReadings); | ||
} | ||
|
||
/** | ||
* @brief Aranet4 measurement intervals | ||
*/ | ||
uint16_t Aranet4::getInterval() { | ||
return getU16Value(UUID_Aranet4, UUID_Aranet4_Interval); | ||
} | ||
|
||
/** | ||
* @brief Aranet4 device name | ||
*/ | ||
String Aranet4::getName() { | ||
return getStringValue(UUID_Generic, UUID_Generic_DeviceName); | ||
} | ||
|
||
/** | ||
* @brief Aranet4 software version | ||
*/ | ||
String Aranet4::getVersion() { | ||
return getStringValue(UUID_Common, UUID_Common_SwRev); | ||
} | ||
|
||
/** | ||
* @brief Status code of last action | ||
*/ | ||
ar4_err_t Aranet4::getStatus() { | ||
return status; | ||
} | ||
|
||
/** | ||
* @brief Reads raw data from Aranet4 | ||
* @param [in] serviceUuid GATT Service UUID to read | ||
* @param [in] charUuid GATT Char UUID to read | ||
* @param [out] data Pointer to where received data will be stored | ||
* @param [in|out] Size of data on input, received data size on output (truncated if larger than input) | ||
* @return Read status code (AR4_READ_*) | ||
*/ | ||
ar4_err_t Aranet4::getValue(BLEUUID serviceUuid, BLEUUID charUuid, uint8_t* data, uint16_t* len) { | ||
if (pClient == nullptr) return AR4_ERR_NO_CLIENT; | ||
|
||
if (!aranetCallbacks->isAuthenticated()) return AR4_ERR_UNAUTHORIZED; | ||
if (!aranetCallbacks->isConnected()) return AR4_ERR_NOT_CONNECTED; | ||
|
||
BLERemoteService* pRemoteService = pClient->getService(serviceUuid); | ||
if (pRemoteService == nullptr) { | ||
return AR4_ERR_NO_GATT_SERVICE; | ||
} | ||
|
||
BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(charUuid); | ||
if (pRemoteCharacteristic == nullptr) { | ||
return AR4_ERR_NO_GATT_CHAR; | ||
} | ||
|
||
// Read the value of the characteristic. | ||
if(pRemoteCharacteristic->canRead()) { | ||
std::string str = pRemoteCharacteristic->readValue(); | ||
if (str.length() < *len) *len = str.length(); | ||
memcpy(data, str.c_str(), *len); | ||
return AR4_OK; | ||
} | ||
|
||
return AR4_FAIL; | ||
} | ||
|
||
/** | ||
* @brief Reads string value from Aranet4 | ||
* @param [in] serviceUuid GATT Service UUID to read | ||
* @param [in] charUuid GATT Char UUID to read | ||
* @return String value | ||
*/ | ||
String Aranet4::getStringValue(BLEUUID serviceUuid, BLEUUID charUuid) { | ||
uint8_t buf[33]; | ||
uint16_t len = 32; | ||
status = getValue(serviceUuid, charUuid, buf, &len); | ||
buf[len] = 0; // trerminate string | ||
return String((char *) buf); | ||
} | ||
|
||
/** | ||
* @brief Reads u16 value from Aranet4 | ||
* @param [in] serviceUuid GATT Service UUID to read | ||
* @param [in] charUuid GATT Char UUID to read | ||
* @return u16 value | ||
*/ | ||
uint16_t Aranet4::getU16Value(BLEUUID serviceUuid, BLEUUID charUuid) { | ||
uint16_t val = 0; | ||
uint16_t len = 2; | ||
status = getValue(serviceUuid, charUuid, (uint8_t *) &val, &len); | ||
|
||
if (len == 2) { | ||
return val; | ||
} | ||
|
||
status = AR4_FAIL; | ||
return 0; | ||
} |
Oops, something went wrong.