BLE Smart Thermal Flask by M5Stack

1 47198 Easy

Thermal Flask that senses the inside temperature and sends the information to a receiver via Bluetooth.

projectImage

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.

projectImage

Things that you need:

M5Stick C

M5Stamp Pico

LM35 Temperature Sensor

 

Get PCBs for Your Projects Manufactured

projectImage

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):

projectImage

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:

UIFlow

MicroPython

Arduino

.NET nanoFramework

 

M5Stamp Pico (Source from M5Stack):

projectImage

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:

projectImage

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:

projectImage

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.

CODE
#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:

projectImage

And these lines of code contain the basic LM35's calibration readings, don't change these.

projectImage

This is the BLE Service ID to the transmitter:

projectImage

Here is the service ID for the temperature data.

projectImage

M5Stamp Pico doesn't have any reset button, but it has a user-defined button, here I used that one to reset the board.

projectImage

Finally, upload the code to the M5Stamp Pico, and make sure you have selected the correct board settings:

projectImage

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.

CODE
#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.

projectImage

I have added some lines of code to show the Temperature reading to the TFT Display.

projectImage

Once done, with the needed changes, upload the code to the M5Stick C.

projectImage
projectImage

After uploading the code once, press the reset button on the transmitter and the receiver and monitor the serial outputs.

projectImage

The sensor readings will be uploaded each 10 seconds

projectImage

I added this with my coffee flask.

projectImage
projectImage
License
All Rights
Reserved
licensBg
1