/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* IoT CHALLENGE 1 - PARKING OCCUPANCY NODE *
* This node periodically communicates to a central ESP32 sink the occupancy of *
* a parking spot, based on the ultrasonic distance measured by an HC-SR04. *
* Developed by: Pontiggia Anna Margherita (person code 10623834) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <esp_now.h>
#include <WiFi.h>
// Given in the specifications:
#define DISTANCE 50
#define SLEEP_s 39 // X = 34 mod 50 + 5
// HC-SR04:
#define PIN_TRIG 12
#define PIN_ECHO 14
#define TRIG_us 10 // TRIG of HC-SR04 is to be set HIGH for 10us or more.
#define INTO_cm 58 // Proportionality factor to have the distance in cm.
// Others:
#define INTO_us 1000000
#define WAIT_us 600 // To be sure the message is transmitted to the sink.
#define DEBUG true // If set TRUE will print timings and received message.
// Sink information:
uint8_t address[] = {0x8C, 0xAA, 0xB5, 0x84, 0xFB, 0x90};
esp_now_peer_info_t sink;
/* Callback function that is executed everytime a message is sent.
It prints whether the data transmission was successful or not. */
void OnDataSent(const uint8_t *mac_address, esp_now_send_status_t status) {
Serial.print(" > Send status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "SUCCESS" : "FAILURE");
}
/* Callback function that is executed every time a message is received.
It prints the message once is received. */
void OnDataRecv(const uint8_t *mac_address, const uint8_t *data, int length) {
if(DEBUG) {
char message[length];
memcpy(message, data, length);
Serial.print(" > Message received: " + String(message) + "\n");
}
}
/* Function that measures the distance using the HC-SR04.
It returns TRUE when the slot is empty (distance measured < 50 cm). */
bool spotIsEmpty() {
float dist_cm;
// INITIALIZATION: TRIG is set to HIGH until ECHO goes HIGH.
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(TRIG_us);
// MEASUREMENT: the distance is proportional to the time ECHO stays HIGH.
digitalWrite(PIN_TRIG, LOW);
dist_cm = pulseIn(PIN_ECHO, HIGH) / INTO_cm;
Serial.println(" > Distance measured: " + String(dist_cm) + " cm");
return dist_cm >= DISTANCE;
}
/* Main function that sets up ESP32, HC-SR04 and network functionality.
It also manages the functionalities of the sensor node (distance measurement,
message transmission and deep sleep). It is executed every time the node wakes
up after a deep sleep. The time usage is printed at the end of every phase. */
void setup() {
unsigned long t_wake, t_boot, t_sens, t_wifi, t_send, t_off, t_sleep;
bool empty_spot;
String message;
// Wake-up time:
t_wake = micros();
// SENSOR NODE INITIALIZATION (BOOT PHASE): ------------------------------------
Serial.begin(115200);
Serial.println("\nInitialization...");
// Pins setup, according to the working of the HC-SR04:
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
// End-of-boot time:
t_boot = micros();
// MEASUREMENT by HC-SR04 (SENSOR-READING PHASE): ------------------------------
Serial.println("Measurement...");
empty_spot = spotIsEmpty();
Serial.print(" > Parking spot: ");
Serial.println(empty_spot ? "EMPTY" : "OCCUPIED");
// End-of-sensor-reading time:
t_sens = micros();
// NETWORK SETUP (IDLE / WIFI-ON PHASE): ---------------------------------------
Serial.println("Setting up network...");
// WiFi enabling:
WiFi.mode(WIFI_STA);
WiFi.setTxPower(WIFI_POWER_2dBm);
// esp_now initalization and callback functions registration:
esp_now_init();
esp_now_register_send_cb(OnDataSent);
esp_now_register_recv_cb(OnDataRecv);
// Sink registration as a peer:
memcpy(sink.peer_addr, address, 6);
sink.channel = 0;
sink.encrypt = false;
esp_now_add_peer(&sink);
// End-of-network-initialization time:
t_wifi = micros();
// SLOT OCCUPANCY TRANSMISSION TO THE SINK (TRANSMISSION PHASE): ---------------
Serial.println("Sending message to sink ESP32...");
message = empty_spot ? "FREE" : "OCCUPIED";
esp_now_send(address, (uint8_t*)message.c_str(), message.length() + 1);
// Wait for message transmission (IDLE / WIFI-ON PHASE)
delayMicroseconds(WAIT_us);
t_wifi = t_wifi + WAIT_us;
// End-of-transmission time:
t_send = micros();
// WIFI SHUTDOWN (IDLE / WIFI-ON PHASE): ---------------------------------------
Serial.println("Turning off the Wi-Fi..");
WiFi.mode(WIFI_OFF);
// Wifi-shutting time:
t_off = micros();
// PREPARATIONS FOR DEEP SLEEP (IDLE / WIFI-OFF PHASE): ------------------------
Serial.println("Preparing to go into deep sleep state...");
// Set timer to wake up device:
esp_sleep_enable_timer_wakeup(SLEEP_s * INTO_us);
// Time usage printing:
if(DEBUG) {
Serial.println("Time usage for each phase:");
Serial.println(" > Hardware setup: " + String(t_boot - t_wake) + " us");
Serial.println(" > Sensor reading: " + String(t_sens - t_boot) + " us");
Serial.println(" > Network setup & wait: " + String(t_wifi - t_sens) + " us");
Serial.println(" > Transmission: " + String(t_send - t_wifi) + " us");
Serial.println(" > WiFi disabling: " + String(t_off - t_send) + " us");
}
//Waiting for all serial output to be transmitted
Serial.flush();
// End-of-preparation time:
t_sleep = micros();
if(DEBUG) {
Serial.println(" > Idle (WiFi off): " + String(t_sleep - t_off) + " us");
}
// DEEP SLEEP PHASE: -----------------------------------------------------------
Serial.println("Going to sleep for " + String(SLEEP_s) + " s...\n");
esp_deep_sleep_start();
}
/* Function executed in loop when the sensor node is active and set.
Due to the deep sleep called at the end of setup it is never reached. */
void loop() {}