/*|-----------------------------------------------------------------------------------|*/
/*|Project: Ultrasonic sensor node ESP32 with HTTP connectivity (FreeRTOS) |*/
/*|ESP32 (DevKit, Generic) - ESP-IDF v4.2 (4.0 compatible) |*/
/*|Compatible sensors: HC-SR04 / JSN-SR04T / HY-SRF05 / Parallax PING)))™, DYP-ME007..|*/
/*|Author: martinius96 |*/
/*|E-mail: [email protected] |*/
/*|Project info: https://martinius96.github.io/hladinomer-studna-scripty/en/ |*/
/*|Test web interface: http://arduino.clanweb.eu/studna_s_prekladom/?lang=en |*/
/*|On this web interface there is ESP32 sending datas each 5 minututes |*/
/*|Buy me a coffee at: paypal.me/chlebovec |*/
/*|-----------------------------------------------------------------------------------|*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "ultrasonic.h"
#include "driver/dac.h"
/* Constants that aren't configurable in menuconfig */
#define MAX_DISTANCE_CM 450 // 5m max
#define GPIO_TRIGGER 22
#define GPIO_ECHO 23
// Webserver
#define WEB_SERVER "arduino.clanweb.eu"
#define WEB_PORT "80"
static const char *TAG = "http_request";
static const char *TAG2 = "ultrasonic_measurement";
// WiFi parameters
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASS ""
// Event group
static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
QueueHandle_t q = NULL;
static void ultrasonic(void *pvParamters)
{
ultrasonic_sensor_t sensor = {
.trigger_pin = GPIO_TRIGGER,
.echo_pin = GPIO_ECHO
};
ultrasonic_init(&sensor);
uint32_t distance = 0;
if (q == NULL) {
printf("Queue is not ready \n");
return;
}
while (true) {
uint32_t avg_distance = 0;
int index_loop = 1;
while (index_loop <= 10) {
esp_err_t res = ultrasonic_measure_cm(&sensor, MAX_DISTANCE_CM, &distance);
if (res != ESP_OK) {
printf("Error: ");
switch (res) {
case ESP_ERR_ULTRASONIC_PING:
printf("Cannot ping (device is in invalid state)\n");
break;
case ESP_ERR_ULTRASONIC_PING_TIMEOUT:
printf("Ping timeout (no device found)\n");
break;
case ESP_ERR_ULTRASONIC_ECHO_TIMEOUT:
printf("Echo timeout (i.e. distance too big)\n");
break;
default:
printf("%d\n", res);
}
} else {
printf("Measurement %d: %d cm\n", index_loop, distance);
avg_distance += distance;
index_loop++;
}
}
avg_distance = avg_distance / 10;
distance = avg_distance;
xQueueSend(q, (void *)&distance, (TickType_t )0); // add the counter value to the queue
for (int countdown = 300; countdown >= 0; countdown--) {
printf("Next measurement in %d seconds\n", countdown);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
static void http_get_task(void *pvParameters)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
int s, r;
char recv_buf[64];
uint32_t distance;
if (q == NULL) {
printf("Queue is not ready \n");
return;
}
while (1) {
xQueueReceive(q, &distance, portMAX_DELAY);
char REQUEST [1000];
char values [250];
sprintf(values, "hodnota=%d&token=123456789", distance);
sprintf (REQUEST, "POST /studna_s_prekladom/data.php HTTP/1.0\r\nHost: "WEB_SERVER"\r\nUser-Agent: ESP32\r\nConnection: close\r\nContent-Type: application/x-www-form-urlencoded;\r\nContent-Length:%d\r\n\r\n%s\r\n",strlen(values),values);
int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
if (err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
s = socket(res->ai_family, res->ai_socktype, 0);
if (s < 0) {
ESP_LOGE(TAG, "... Failed to allocate socket.");
freeaddrinfo(res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... allocated socket");
if (connect(s, res->ai_addr, res->ai_addrlen) != 0) {
ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
close(s);
freeaddrinfo(res);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... connected");
freeaddrinfo(res);
if (write(s, REQUEST, strlen(REQUEST)) < 0) {
ESP_LOGE(TAG, "... socket send failed");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... socket send success");
struct timeval receiving_timeout;
receiving_timeout.tv_sec = 5;
receiving_timeout.tv_usec = 0;
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
sizeof(receiving_timeout)) < 0) {
ESP_LOGE(TAG, "... failed to set socket receiving timeout");
close(s);
vTaskDelay(4000 / portTICK_PERIOD_MS);
continue;
}
ESP_LOGI(TAG, "... set socket receiving timeout success");
/* Read HTTP response */
do {
bzero(recv_buf, sizeof(recv_buf));
r = read(s, recv_buf, sizeof(recv_buf) - 1);
for (int i = 0; i < r; i++) {
putchar(recv_buf[i]);
}
} while (r > 0);
ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);
close(s);
ESP_LOGI(TAG, "Starting again!");
}
}
// Wifi event handler
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
// Main task
void main_task(void *pvParameter)
{
tcpip_adapter_ip_info_t ip_info;
// wait for connection
printf("Waiting for connection to the wifi network... \n");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
printf("Connected!\n");
// print the local IP address
ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
printf("IP Address: %s\n", ip4addr_ntoa(&ip_info.ip));
printf("Subnet mask: %s\n", ip4addr_ntoa(&ip_info.netmask));
printf("Gateway: %s\n", ip4addr_ntoa(&ip_info.gw));
if (q != NULL) {
printf("Queue is created\n");
vTaskDelay(1000 / portTICK_PERIOD_MS); //wait for a second
xTaskCreate(&ultrasonic, "ultrasonic", 2048, NULL, 5, NULL);
printf("producer task started\n");
xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, 5, NULL);
printf("consumer task started\n");
} else {
printf("Queue creation failed");
}
while (1) {
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
// Main application
void app_main()
{
printf("ESP-IDF version used: ");
printf(IDF_VER"\n");
// disable the default wifi logging
esp_log_level_set("wifi", ESP_LOG_NONE);
// initialize NVS
ESP_ERROR_CHECK(nvs_flash_init());
// create the event group to handle wifi events
wifi_event_group = xEventGroupCreate();
// initialize the tcp stack
tcpip_adapter_init();
// initialize the wifi event handler
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
// initialize the wifi stack in STAtion mode with config in RAM
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// configure the wifi connection and start the interface
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
},
};
// start the main task
xTaskCreate(&main_task, "main_task", 2048, NULL, 5, NULL);
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
printf("Connecting to %s\n", WIFI_SSID);
q = xQueueCreate(20, sizeof(unsigned long));
}