Julien MonginRemi DROUINVictor DuboisThibault Gautier
Published © GPL3+

ST Connect (Dike Monitoring)

ST Connect is an autonomous connected object that collect and send data, in order to monitore dikes in the Barcellonette. #PolytechSorbonne

IntermediateFull instructions provided15 hours877
ST Connect (Dike Monitoring)

Things used in this project

Hardware components

STMicroelectronics nucleo_l432kc
Low consuming mirocontroller
×1
Seeed Studio Grove 101990019
×1
DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1
DFRobot SEN0193
×1
Grove - Barometer (High-Accuracy)
Seeed Studio Grove - Barometer (High-Accuracy)
×1
Honeywell HMC5883L
This component is actually a QMC5883L
×1
Sigfox BRKWS01
×1
Accu Li-Ion 3,7V 1050mA
×1
Microchip MCP73831T
×1
Maxim Integrated MAX1921EUT33
×1
TE Connectivity PRASA1-16F-BB0BW
×1
SOL1W
×1

Software apps and online services

Sigfox
Sigfox

Story

Read more

Custom parts and enclosures

Gerber file of the PCB (part 1)

Use this file to print the PCB with a PCB engraver

Gerber file of the PCB (part 2)

Use this file to print the PCB with a PCB engraver

Prining file of the box (part 1)

Use this file to print the box with a 3D printed device

Printing file of the box (part 2)

Use this file to print the box with a 3D printed device

Zip file of Kikad project of the PCB

Use these files to modify the PCB

Schematics

PCB shematic

Overall fonctioning

This diagram explain how the algorithm works

Technical drawing

Settings for the callback on SigFox website

Use this settings on SigFox website to redirect the data on our web interface

Complete URL : "http://yoururl.com/sigfox/?id={device}&time={time}&data={customData#data}&data2={customData#data2}"

Code

Defines

C/C++
Five “ENABLE” are used to initialize the objects linked to the sensors, “MESSAGE SIZE” and “TRAME SIZE” are used to build AT commands. “DEBUG” is used to send informations on the serial port and “SEND_SIGFOX” is used to allow the message to be sent.
If you want to disable one of the feature
just comment the line.
// Time during the deepsleep in ms
#define DEEPSLEEP_TIME (12*60000)

// Enabling components
#define ENABLE_BAROMETER 1
#define ENABLE_MAGNETOMETER 1
#define ENABLE_GROUND_TEMPERATURE 1
#define ENABLE_GROUND_HUMIDITY 1
#define ENABLE_DHT22 1

// Sigfox constants
#define MESSAGE_SIZE 32
#define TRAME_SIZE 25

// Enable the debug
// #define DEBUG

// Enable the sending over Sigfox
#define SEND_SIGFOX 1

// Object initializations
#ifdef DEBUG
    Serial pc(USBTX, USBRX);
    DigitalOut myled(LED1);
#endif

#ifdef ENABLE_BAROMETER
    HP20x_dev capt_barometer(D4, D5);
#endif

#ifdef ENABLE_MAGNETOMETER
    QMC5883L capt_magnetometer(D4, D5);
#endif

#ifdef ENABLE_GROUND_TEMPERATURE
    DS1820 capt_ground_temperature(A1);
#endif

#ifdef ENABLE_GROUND_HUMIDITY
    DigitalOut transistor_humidity(D12);
    AnalogIn capt_ground_humidity(A0);      // SEN0
#endif

#ifdef ENABLE_DHT22
    DHT22 capt_thermo_air_humidity(D3);     // DHT22
#endif

SigFox format

C/C++
With the Sigfox network, we can only send 140 messages of 3 bytes per day, so we have to use a specific format to be able to send our data in 3 bytes.
We cannot send a message every 10 minutes (144 messages per day), so we chose to send a message every 12 minutes (120 message per day).
/*
 * Format the trame to send over Sigfox
 * Put the trame in *v_trame
 */
void format(float v_ground_temperature, float v_air_temperature, float v_ground_humidity, float v_air_humidity, long v_pressure, int16_t* v_magnetic_field, char* v_trame)
{
    // Converting our data to use as few bits as possible
    int16_t i_ground_temperature = (int16_t) round(v_ground_temperature * 10);
    int16_t i_air_temperature = (int16_t) round(v_air_temperature * 10);
    int16_t i_ground_humidity = (int16_t) round(v_ground_humidity);
    int16_t i_air_humidity = (int16_t) round(v_air_humidity);
    int32_t i_pressure = (int32_t) v_pressure;
    bool err[3] = {false, false, false};    // magnetic field error x,y,z
    
    // Checking if the values are in the range
    if(!(i_ground_temperature >= -512 && i_ground_temperature < 511))
        i_ground_temperature = -512;
        
    if(!(i_air_temperature >= -512 && i_air_temperature < 511))
        i_air_temperature = -512;
    
    if(!(i_ground_humidity <= 100))
        i_ground_humidity = 127;
    
    if(!(i_air_humidity <= 100))
        i_air_humidity = 127;
    
    if(!(i_pressure <= 131071))
        i_pressure = 0;
    
    unsigned int i;
    for(i = 0; i < 3; i++)
    {
        if(!(v_magnetic_field[i] > -65536 && v_magnetic_field[i] < 65535))
            err[i] = true;
    }
    
    // Putting them in the trame
    snprintf(v_trame, TRAME_SIZE, "%02x", (char)(i_ground_temperature >> 2));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((i_ground_temperature << 6) | ((i_air_temperature >> 4) & 0x3f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((i_air_temperature << 4) | ((i_ground_humidity >> 3) & 0x0f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((i_ground_humidity << 5) | ((i_air_humidity >> 2) & 0x1f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((i_air_humidity << 6) | ((i_pressure >> 11) & 0x3f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)(i_pressure >> 3));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((i_pressure << 5) | ((v_magnetic_field[0] >> 9) & 0x1f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)(v_magnetic_field[0] >> 1));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((v_magnetic_field[0] << 7) | ((v_magnetic_field[1] >> 7) & 0x7f)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((v_magnetic_field[1] << 1) | ((v_magnetic_field[2] >> 13) & 0x01)));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)(v_magnetic_field[2] >> 5));
    snprintf(v_trame, TRAME_SIZE, "%s%02x", v_trame, (char)((v_magnetic_field[2] << 3) | (err[0] << 2) | (err[1] << 1) | (err[2])));
}

Main

C/C++
Available on the repository of the project on Mbed :
https://os.mbed.com/users/raminou/code/projet_st_connect/
int main()
{
    #ifdef DEBUG
        pc.printf("\r\n\r\n\r\nInit...\r\n");
    #endif
    
    sigfox.printf("\r\n");
    
    #ifdef ENABLE_BAROMETER
    if(capt_barometer.isAvailable())
        pressure = capt_barometer.ReadPressure();
    #endif
    
    #ifdef ENABLE_MAGNETOMETER
        capt_magnetometer.init();
    #endif
    
    wait(5);
    
    // Main loop
    while(1) {
        #ifdef DEBUG
            myled = 1;
            wait(5);
            myled = 0;
        #endif
        
        #ifdef ENABLE_GROUND_HUMIDITY
            // Plug the ground humidity
            transistor_humidity = 1;
        #endif
        
        // Wake Up sigfox
        reset_sigfox.output();
        reset_sigfox = 0;
        wait(5);
        
        // Set high impendance the sigfox reset pin
        reset_sigfox.input();
        
        #ifdef ENABLE_GROUND_TEMPERATURE
            // Ground Temperature
            capt_ground_temperature.convertTemperature(true, DS1820::all_devices);
            ground_temperature = capt_ground_temperature.temperature();
        #endif
        
        #ifdef ENABLE_GROUND_HUMIDITY
            // Ground Humidity
            ground_humidity = capt_ground_humidity.read() * 100;
            transistor_humidity = 0;
        #endif
        
        #ifdef ENABLE_DHT22
            // Air temperature and humidity
            if(capt_thermo_air_humidity.sample())
            {
                air_temperature = capt_thermo_air_humidity.getTemperature() / 10.0;
                air_humidity = capt_thermo_air_humidity.getHumidity() / 10.0;
            }
        #endif
        
        #ifdef ENABLE_BAROMETER
            // Pressure
            if(capt_barometer.isAvailable())
                pressure = capt_barometer.ReadPressure();
        #endif
        
        #ifdef ENABLE_MAGNETOMETER
            // Magnetometer
            capt_magnetometer.init();
            magnetic_field[0] = capt_magnetometer.getMagXvalue();
            magnetic_field[1] = capt_magnetometer.getMagYvalue();
            magnetic_field[2] = capt_magnetometer.getMagZvalue();
            capt_magnetometer.standby();
        #endif
        
        #ifdef DEBUG
            // Display to check your values
            pc.printf("\r\n");
            pc.printf("Pressure: %f hPa\r\n", pressure/100.0);
            pc.printf("Ground Temperature: %f\t|\t", ground_temperature);
            pc.printf("Ground Humidity: %.1f\r\n", ground_humidity);
            pc.printf("Air Temperature: %.1f\t|\tAir Humidity: %.1f\r\n", air_temperature, air_humidity);
            pc.printf("Magnetic field: x: %hd, y: %hd, z: %hd\r\n", magnetic_field[0], magnetic_field[1], magnetic_field[2]);
        #endif
        
        // Creating your sigfox trame
        format(ground_temperature, air_temperature, ground_humidity, air_humidity, pressure, magnetic_field, &(message[6]));
        message[MESSAGE_SIZE-2] = '\r';
        message[MESSAGE_SIZE-1] = '\n';
        #ifdef DEBUG
            pc.printf("msg=%s", message);
        #endif
        
        // Sending over sigfox
        #ifdef SEND_SIGFOX
            sigfox.printf("%s", message);
            wait(8);    // Time during the sigfox module is sending, do not stop the sigfox before !
        #endif
        
        // Sleep Sigfox
        sigfox.printf("AT$P=1\r\n");
        
        #ifdef DEBUG
            // Detect that the system is going in sleep mode
            pc.printf("Sleep");
            myled = 1;
            wait(0.3);
            myled = 0;
            wait(0.3);
            myled = 1;
            wait(0.3);
            myled = 0;
            wait(0.3);
            myled = 1;
            wait(0.3);
            myled = 0;
        #endif
                
        // Deepsleep
        if(disable_deep == 0)
        {
            WakeUp::set_ms(DEEPSLEEP_TIME);
            WakeUp::attach(&mycallback);
            deepsleep();
        }
    }
}

Libraries

C/C++
Before starting the project, we have found four libraries (DHT22.h, HP20x_dev.h, DS1820.h and QMC5883L.h) to obtain measures from the four active sensors. Then we have add WakeUp.h to manage microcontroller deepsleep and mbed.h to use the Mbed functions.
But we have made some modifications on these libraries to adapt it to our project, so make sure you use libraries from our project to have all the modifications.
#include "mbed.h"
#include "WakeUp.h"
#include "DHT22.h"
#include "HP20x_dev.h"
#include "DS1820.h"
#include "QMC5883L.h"

Setup and Fonctions

C/C++
// Pin to disable deepsleep
DigitalIn disable_deep(D6);

Serial sigfox(D1, D0);

// Pin to control the transistor
DigitalInOut reset_sigfox(D9);


char message[MESSAGE_SIZE] = "AT$SF=";

// Default values at the init
long pressure = 10000;
float air_temperature = 20.0;
float air_humidity = 50.0;
float ground_temperature = 20.0;
float ground_humidity = 0.5;
int16_t magnetic_field[3] = {}; // x, y, z

/*
 * Empty callback of the deepsleep because in this version of mbed, the wakeup
 * does not work without it. 
 * But the code inside it is not executed !
 */
void mycallback()
{
}

/*
 * Round the float f
 */
int16_t round(float f)
{
    int16_t res = (int16_t)f;
    if (f - res > 1/2) 
        res++;
        
    return res;
}

Web interface

In order to deploy, read file named "README", in the repository

Credits

Julien Mongin

Julien Mongin

2 projects • 1 follower
Remi DROUIN

Remi DROUIN

2 projects • 2 followers
Victor Dubois

Victor Dubois

2 projects • 1 follower
Thibault Gautier

Thibault Gautier

2 projects • 1 follower

Comments