Thermal Flask that senses the inside temperature and sends the information to a receiver via Bluetooth.
Hey, what's up, Guys! Akarsh here from CETech.
In this tutorial, I'm going to show you how to transfer the sensor readings between two ESP32 Boards via Bluetooth protocol.
Things that you need:
M5Stick C
M5Stamp Pico
LM35 Temperature Sensor
Get PCBs for Your Projects Manufactured
You must check out PCBWAY for ordering PCBs online for cheap!
You get 10 good-quality PCBs manufactured and shipped to your doorstep for cheap. You will also get a discount on shipping on your first order. Upload your Gerber files onto PCBWAY to get them manufactured with good quality and quick turnaround time. PCBWay now could provide a complete product solution, from design to enclosure production. Check out their online Gerber viewer function. With reward points, you can get free stuff from their gift shop.
M5Stick C (Source from M5Stack):
M5StickC is a mini M5Stack, powered by ESP32. It is a portable, easy-to-use, open-source, IoT development board. What it can do? This tiny block is able to realize your idea, enlighten your creativity, and help with your IoT prototyping in a very short time. It will take away a lot of pains from the development process.M5stickC is one of the core devices in the M5Stack product series.
It is built in a continually growing hardware and software ecosystem. It has a lot of compatible modules and units, as well as the open-source code & engineering communities that will help you maximize your benefits in every step of the developing process.
-------------------------------------------->Buy Link<----------------------------------------------------
Power switch operation:
Power on: Press the power button for 2 seconds
Power off: Press the power button for 6 seconds
Notice:
Baud rate supported by M5StickC: 1200 ~115200, 250K, 500K, 750K, 1500K
Product Features
ESP32-based
Built-in 6-Axis IMU
Red LED
IR transmitter
Microphone
Buttons, LCD(0.96 inch)
Built-in Lipo Battery
Extendable Socket
Wearable & Wall-mounted
Compatible with multi-platform development:
M5Stamp Pico (Source from M5Stack):
STAMP-PICO features an ultra-compact design with two low-power Xtensa® 32-bit LX6 microprocessors at 240MHz on a PCB as tiny and delicate as a postage stamp. low power consumption. It is ideal for any space-constrained or battery-powered devices such as wearables, medical devices, sensors, and other IoT devices.
1, MULTIFORM: 5 options of installation, means endless possibilities! (SMT, DIP, flywire, grove interface), with a high-temperature resistant plastic shell, 3D antenna and components can be better protected.
2, LOW-CODE DEVELOPMENT: STAMP-PICO supports UIFlow graphical programming platform, scripting-free, cloud push; and fully compatible with Arduino, MicroPython, ESP32-IDF, and other mainstream development platforms to quickly build various applications.
3, HIGH INTEGRATION: STAMP-PICO contains a 5V->3.3V DC/DC port, GPIOx12, programmable RGB light x1, button x1, finely tuned RF circuit, providing stable and reliable wireless communication.
4, STRONG EXPANDABILITY: Easy access to M5Stack's hardware and software ecology system: a wealth of sensors, actuators, functional modules, and accessories to choose from, and extremely fast adaptation.
-------------------------------------------->Buy Link<--------------------------------------------
Product Features
Chip-set:ESP32-PICO-D4 (2.4GHz Wi-Fi dual mode)
Support UIFlow graphical programming
Multi-IO pinout, support multiple application forms (SMT, DIP, fly-by-wire)
Integrated programmable RGB LEDs and buttons
Miniature module
LM35 Temperature Sensor:
The LM35 is an integrated analog temperature sensor whose output is proportional to degrees centigrade. Sensors such as the LM35 do not require external calibration or trimming to provide typical accuracy. LM35's low output impedance, a linear output, and accurate inherent calibration make it especially easy to interface with readouts and control circuits.
Hardware Connections:
Connect the LM35's output pin to M5Stamp's 36th pin and LM35's power to 5 V and GND to GND of the PICO.
VOUT - > G36
GND - > GND
VCC - > 5V
That's all we need for this tutorial.
Programming the Transmitter:
In this tutorial, M5Stamp pico will act as a transmitter, and it will send a temperature reading to the transmitter once it is connected to the transmitter. You can access the code through the Github repository of the project from here. The file named “Transmitter.ino” is the code for the transmitter.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <FastLED.h>
// LED Count
#define NUM_LEDS 1
#define DATA_PIN 27
// Define the array of leds
CRGB leds[NUM_LEDS];
#define Button 39
//BLE server name
#define bleServerName "M5"
//LM35
#define ADC_VREF_mV 3300.0 // in millivolt
#define ADC_RESOLUTION 4096.0
#define PIN_LM35 36 // ESP32 pin GIOP36 (ADC0) connected to LM35
float temp;
float tempF;
float hum;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
bool deviceConnected = false;
#define SERVICE_UUID "91bad492-b950-4226-aa2b-4ede9fa42f59"
// Temperature Characteristic and Descriptor
BLECharacteristic bmeTemperatureCelsiusCharacteristics("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor bmeTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));
//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
// Start serial communication
Serial.begin(115200);
FastLED.addLeds<SK6812, DATA_PIN, RGB>(leds, NUM_LEDS);
pinMode(Button, INPUT);
// Create the BLE Device
BLEDevice::init(bleServerName);
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *bmeService = pServer->createService(SERVICE_UUID);
// Create BLE Characteristics and Create a BLE Descriptor
bmeService->addCharacteristic(&bmeTemperatureCelsiusCharacteristics);
bmeTemperatureCelsiusDescriptor.setValue("BME temperature Celsius");
bmeTemperatureCelsiusCharacteristics.addDescriptor(&bmeTemperatureCelsiusDescriptor);
// Start the service
bmeService->start();
// Start advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
static bool State;
State = digitalRead(Button);
if (State == 0)
{
ESP.restart();
}
if (deviceConnected) {
if ((millis() - lastTime) > timerDelay) {
// Turn the LED on, then pause
leds[0] = 0xf00000;
FastLED.show();
delay(2000);
// read the ADC value from the temperature sensor
int adcVal = analogRead(PIN_LM35);
// convert the ADC value to voltage in millivolt
float milliVolt = adcVal * (ADC_VREF_mV / ADC_RESOLUTION);
// convert the voltage to the temperature in °C
temp = milliVolt / 10;
static char temperatureCTemp[6];
dtostrf(temp, 6, 2, temperatureCTemp);
//Set temperature Characteristic value and notify connected client
bmeTemperatureCelsiusCharacteristics.setValue(temperatureCTemp);
bmeTemperatureCelsiusCharacteristics.notify();
// Now turn the LED off, then pause
leds[0] = 0x00f000;
FastLED.show();
Serial.print("Temperature Celsius: ");
Serial.print(temp);
Serial.println(" ºC");
lastTime = millis();
}
}
}
In this code, if you need to change your BLE Server name then change this line as per your needs:
And these lines of code contain the basic LM35's calibration readings, don't change these.
This is the BLE Service ID to the transmitter:
Here is the service ID for the temperature data.
M5Stamp Pico doesn't have any reset button, but it has a user-defined button, here I used that one to reset the board.
Finally, upload the code to the M5Stamp Pico, and make sure you have selected the correct board settings:
Programming the Receiver:
In this tutorial, M5Stick C will act as a transmitter, and it will receive the temperature reading from the transmitter. You can access the code through the Github repository of the project from here. The file named “Receiver.ino” is the code for the receiver.
#include <M5StickC.h>
#include "BLEDevice.h"
//BLE Server name
#define bleServerName "M5"
/* UUID's of the service, characteristic that we want to read*/
// BLE Service
static BLEUUID bmeServiceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59");
//Temperature Celsius Characteristic
static BLEUUID temperatureCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");
//Flags stating if should begin connecting and if the connection is up
static boolean doConnect = false;
static boolean connected = false;
//Address of the peripheral device. Address will be found during scanning...
static BLEAddress *pServerAddress;
//Characteristicd that we want to read
static BLERemoteCharacteristic* temperatureCharacteristic;
//Activate notify
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};
//Variables to store temperature and humidity
char* temperatureChar;
//Flags to check whether new temperature and humidity readings are available
boolean newTemperature = false;
//Connect to the BLE Server that has the name, Service, and Characteristics
bool connectToServer(BLEAddress pAddress) {
BLEClient* pClient = BLEDevice::createClient();
// Connect to the remove BLE Server.
pClient->connect(pAddress);
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(bmeServiceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(bmeServiceUUID.toString().c_str());
return (false);
}
// Obtain a reference to the characteristics in the service of the remote BLE server.
temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
if (temperatureCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID");
return false;
}
Serial.println(" - Found our characteristics");
//Assign callback functions for the Characteristics
temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
return true;
}
//Callback function that gets called, when another device's advertisement has been received
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.getName() == bleServerName) { //Check if the name of the advertiser matches
advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
pServerAddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
doConnect = true; //Set indicator, stating that we are ready to connect
Serial.println("Device found. Connecting!");
}
}
};
//When the BLE Server sends a new temperature reading with the notify property
static void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
//store temperature value
temperatureChar = (char*)pData;
newTemperature = true;
}
//function that prints the latest sensor readings in the OLED display
void printReadings() {
M5.update();
//Erase the previous contents in the display
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(RED);
M5.Lcd.setCursor(20, 18);
M5.Lcd.setTextSize(1.8);
M5.Lcd.print("[ ");
M5.Lcd.setTextColor(GREEN);
M5.Lcd.print("BLE Smart Flask");
M5.Lcd.setTextColor(RED);
M5.Lcd.print(" ]");
M5.Lcd.setCursor(18, 40);
M5.Lcd.setTextColor(GREEN);
Serial.print("Temperature:");
M5.Lcd.print("Temperature: ");
Serial.println(temperatureChar);
M5.Lcd.print(temperatureChar);
M5.Lcd.print(" C");
M5.Lcd.setCursor(15, 55);
M5.Lcd.setTextColor(RED);
M5.Lcd.print("---------------------");
float x = atof(temperatureChar);
if (x >= 35.0)
{
Serial.println("It may be a over heat");
M5.Lcd.setCursor(15, 65);
M5.Lcd.setTextColor(RED);
M5.Lcd.print("It's may be over heat");
}
else {
Serial.println("It's ok to drink");
M5.Lcd.setCursor(30, 65);
M5.Lcd.setTextColor(GREEN);
M5.Lcd.print("It's ok to drink");
}
M5.Lcd.setCursor(15, 75);
M5.Lcd.setTextColor(RED);
M5.Lcd.print("---------------------");
}
void setup() {
M5.begin();
M5.Lcd.setRotation(3);
M5.Axp.ScreenBreath(10);
M5.Lcd.setTextColor(RED);
M5.Lcd.setCursor(10, 35);
M5.Lcd.setTextSize(1.8);
//Start serial communication
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
//Init BLE device
BLEDevice::init("");
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(30);
}
void loop() {
if (doConnect == true) {
if (connectToServer(*pServerAddress)) {
Serial.println("We are now connected to the BLE Server.");
M5.Lcd.print("Connected to BLE Server");
//Activate the Notify property of each Characteristic
temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
connected = true;
} else {
Serial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
M5.Lcd.print("Not Connected");
}
doConnect = false;
}
//if new temperature readings are available, print in the OLED
if (newTemperature) {
newTemperature = false;
printReadings();
}
}
In this code, rename the transmitter name the same as yours, and make sure the device service ID and Temperature Data ID match with the transmitter.
I have added some lines of code to show the Temperature reading to the TFT Display.
Once done, with the needed changes, upload the code to the M5Stick C.
After uploading the code once, press the reset button on the transmitter and the receiver and monitor the serial outputs.
The sensor readings will be uploaded each 10 seconds
I added this with my coffee flask.