Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Dawid
  • master
  • mosquitto
  • mqtt_receive
  • nico
5 results

Target

Select target project
  • stirnemann/uni_ete_hepialight_mqtt
1 result
Select Git revision
  • Dawid
  • master
  • mosquitto
  • mqtt_receive
  • nico
5 results
Show changes
Commits on Source (9)
#include <WiFi.h>
#include <PubSubClient.h>
#include <HardwareSerial.h>
#define MATRIX_SIZE 10 // 10x10
#define IMG_DATA_SIZE MATRIX_SIZE * MATRIX_SIZE * 3 //DATA SIZE FOR ONE MATRIX = RGB * MATRIX_SIZE
#define BUFFER_SIZE 128
#define CLUSTER "cluster1"
// WiFi
const char *ssid = "uni-ete2"; // Enter your WiFi name
const char *password = "uni-ete2-esp32"; // Enter WiFi password
// MQTT Broker
const char *mqtt_broker = "192.168.1.101";
const char *topic_send = "fromesp";
const char *topic_img = CLUSTER"/image";
const char *topic_txt = CLUSTER"/text";
const char *topic_size = CLUSTER"/size";
const int mqtt_port = 1883;
// WIFI & MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// UART2
HardwareSerial SerialPort(2); // use UART2
char rcv_buffer[BUFFER_SIZE] = {0};
// MATRIX CLUSTER SIZE
uint8_t cluster_size_x = 1;
uint8_t cluster_size_y = 1;
/**
*@brief
Setup all the peripherals of the ESP32 (UART2 & Software serial).
It will connect automatically to an Hardcoded wifi router,
then it will connect with the MQTT broker.
Finally it will publish a message to the topic,
and will subscribe to the needed sub-topic.
*@params
void
*@return
void
*/
void setup()
{
// Set software serial baud to 115200;
Serial.begin(115200);
// Set UART2 serial
SerialPort.begin(115200, SERIAL_8N1, 16, 17); // RX pin: 16, TX pin: 17
// Connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the Wi-Fi network");
// Connecting to a mqtt broker
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
client.setBufferSize(2000);
while (!client.connected())
{
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str());
if (client.connect(client_id.c_str()))
{
Serial.println("Public EMQX MQTT broker connected");
} else
{
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// Publish and subscribe
client.publish(topic_send, "Hi, I'm ESP32 ^^");
client.subscribe(topic_img);
client.subscribe(topic_txt);
}
/**
*@brief
Send an UART message in Pin TX 17 from UART2.
The message will follow the Hepialight2 custom UART format.
Format :
Header : [0x77]
Len : [0x01-0xFF]
Data[0] : [0x00-0xFF]
Data[n] : [0x00-0xFF]
Crc : [0x00-0xFF] = Data[0] ^ Data[1] ^ Data[n] ^ Len
Footer : [0xAA]
*@params
data : data to send to the Hepialight2
length : length of the data
*@return
void
*/
void send_uart_data(const char* data, uint8_t lenght)
{
// SEND UART PACKET HEADER
SerialPort.print((char)0x77);
SerialPort.print((char)lenght);
// SEND DATA AND COMPUTE CRC
uint8_t crc = 0;
for(int i = 0; i < lenght; i++)
{
if(data[i] == 0x77 || data[i] == 0x10 || data[i] == 0xAA)
{
crc = crc ^ 0x10;
SerialPort.print((char)0x10);
}
crc = crc ^ data[i];
SerialPort.print((char)data[i]);
}
// SEND UART PACKET FOOTER
SerialPort.print((char)(crc ^ lenght));
SerialPort.print((char)0xAA);
}
/**
*@brief
Receive an UART message in Pin RX 17 from UART2.
The received message should follow the Hepialight2 custom UART format.
Format :
Header : [0x77]
Len : [0x01-0xFF]
Data[0] : [0x00-0xFF]
Data[n] : [0x00-0xFF]
Crc : [0x00-0xFF] = Data[0] ^ Data[1] ^ Data[n] ^ Len
Footer : [0xAA]
*@params
received_buffer : Will fill the bufeer with
a null-terminated string with the received data
*@return
void
*/
void receive_uart_data(char* received_buffer)
{
static bool receiving_data = false; // Indicator for data reception
static uint8_t buffer[BUFFER_SIZE]; // Receive buffer
static int buffer_index = 0; // Current buffer index
static int message_length = 0; // Length of the currently received message
static uint8_t expected_crc = 0; // Expected CRC
uint8_t received_crc = 0;
bool ctrl_byte = false;
while(SerialPort.available())
{
uint8_t received_byte = SerialPort.read();
switch(received_byte)
{
case 0x77:
// IF 0x10 just before
if(ctrl_byte)
{
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
continue;
}
// UART HEADER
buffer_index = 0;
receiving_data = false;
break;
case 0xAA:
// IF 0x10 just before
if(ctrl_byte)
{
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
continue;
}
// UART HEADER
receiving_data = false;
if(expected_crc == received_crc)
{
memcpy(received_buffer, buffer, message_length);
buffer[buffer_index] = 0;
return;
}
break;
case 0x10:
// IF 0x10 just before
if(!ctrl_byte)
{
ctrl_byte = true;
continue;
}
// DATA
buffer[buffer_index++] = received_byte;
ctrl_byte = false;
break;
default:
// DATA LEN
if(!receiving_data)
{
message_length = received_byte;
expected_crc = received_byte; // Expected CRC is initialized with the message length
receiving_data = true;
continue;
}
// DATA
// GET MESSAGE CRC
if(buffer_index == message_length)
{
received_crc = received_byte;
continue;
}
// Store message bytes in the buffer
buffer[buffer_index++] = received_byte;
expected_crc ^= received_byte; // Calculate expected CRC
break;
}
}
}
/**
*@brief
Convert the 2d index to a 1d index.
*@params
x : x index on a 2d space.
x : y index on a 2d space.
pitch : the lenght of the 2d space.
*@return
int : 1d array index
*/
int d2_to_flat(uint8_t x, uint8_t y, uint32_t pitch)
{
return (x * pitch) + y;
}
/**
*@brief
Remove the header from the ppm image received from
a mqtt message.
*@params
packet : mqtt packet data that contains the ppm image.
lenght : length of the packet data.
*@return
uint8_t* : returns the mqtt packet pointer offset by the header.
*/
uint8_t* remove_header_from_ppm(uint8_t* packet, unsigned int* length)
{
int cnt = 0;
for(int i = 0; i < *length; i++)
{
if(packet[i] == '\n')
{
cnt++;
}
if(cnt >= 3)
{
*length -= i - 1;
return packet + i + 1;
}
}
return NULL;
}
/**
*@brief
Send the received ppm image to the Hepialight 2 by UART2.
The hepialight2 is adressed by his ID on a 2d space (Example : (0, 0)).
The 24 bits RGB data are refactored in 16 bits data (Hepialigt2 buffer size is limited).
R : 8 bits -> 5 bits
G : 8 bits -> 6 bits
B : 8 bits -> 5 bits
*@params
idx : Hepialight matrix ID-x.
idy : Hepialight matrix ID-y.
data : PPM image data (without PPM header).
lenght : length of the data.
*@return
void
*/
void send_data_to_matrix(uint8_t idx, uint8_t idy, uint8_t* data, uint32_t length)
{
uint8_t raw_data[220];
char header[] = "PT;x,y;IMAGE;";
strcpy((char*)raw_data, header);
raw_data[3] = '0' + idx;
raw_data[5] = '0' + idy;
uint8_t send_len = 13;
// RGB DATA PROCESS
// HARDCODED
for(int x = (cluster_size_y - 1 - idy) * 10; x < (cluster_size_y - idy) * 10; x+=1)
{
for(int y = idx * 30; y < (idx+1) * 30; y+=3)
{
// Serial.println()
int i = d2_to_flat(x, y, 30 * cluster_size_y);
// COMPUTE COLOR IN 16 BITS
uint8_t r = data[i] & 0x1F;
uint8_t g = data[i+1] & 0x3F;
uint8_t b = data[i+2] & 0x1F ;
uint16_t rgb = r << 11 | g << 5 | b;
// SPLIT ON 8 BITS
uint8_t rgb_0 = rgb >> 8;
uint8_t rgb_1 = rgb & 0xFF;
// SEND RGB
raw_data[send_len++] = rgb_0;
raw_data[send_len++] = rgb_1;
}
}
// SEND UART PACKET HEADER
send_uart_data((char*)raw_data, send_len);
}
/**
*@brief
Callback function called when the ESP32 receive a mqtt packet.
Only when the ESP32 is subscribed to the right topic.
*@params
topic : The concerned topic.
payload : Received packet.
data : length of the received packet.
*@return
void
*/
void callback(char *topic, byte *payload, unsigned int length)
{
// TERMINAL SERIAL
Serial.print("Message arrived in topic: ");
Serial.println(topic);
if(strcmp(topic, topic_txt) == 0)
{
char data[100];
char header[] = "PT;0,0;MOVING;16711680;0.1;";
memcpy(data, header, strlen(header) + 1);
// MATRIX ID
data[3] = '0' + cluster_size_x - 1;
data[5] = '0';
strncat(data, (char*)payload, length);
uint32_t len = strlen(data);
// SEND UART PACKET HEADER
SerialPort.print((char)0x77);
SerialPort.print((char)len);
uint8_t crc = 0;
for(int i = 0; i < len; i++)
{
if(data[i] == 0x77 || data[i] == 0x10 || data[i] == 0xAA)
{
crc = crc ^ 0x10;
SerialPort.print((char)0x10);
}
crc = crc ^ data[i];
SerialPort.print((char)data[i]);
}
// SEND UART PACKET FOOTER
SerialPort.print((char)(crc ^ len));
SerialPort.print((char)0xAA);
return;
}
// GET RAW DATA
uint8_t* raw_data = remove_header_from_ppm(payload, &length);
if(raw_data == NULL)
{
return;
}
// SEND UART PACKET FOR EACH MATRIX
for(int x_mat = 0; x_mat < cluster_size_x; x_mat++)
{
for(int y_mat = cluster_size_y - 1; y_mat >= 0; y_mat--)
{
// SEND UART PACKET
send_data_to_matrix(x_mat, y_mat, raw_data, IMG_DATA_SIZE);
}
}
}
/**
*@brief
Main loop. Handle the mqtt callback function.
When the ESP32 receive a "ESP" UART message, it will respond "OK".
When the ESP32 receive a "MATSIZE" message,
it will update the hepialight2 cluster size
and will publish to the /size subtopic to signal the broker.
*@params
idx : Hepialight matrix ID-x
idy : Hepialight matrix ID-y
data : PPM image data (without PPM header)
lenght : length of the data.
*@return
void
*/
void loop()
{
client.loop();
receive_uart_data(rcv_buffer); // READ UART BUFFER
// CHECK PRESENCE FROM HEPIALIGHT
if(strcmp(rcv_buffer, "ESP") == 0)
{
Serial.println(rcv_buffer);
rcv_buffer[0] = 0; // CLEAR BUFFER
send_uart_data("OK", 2); // SEND OK
}
// SET MATRIX SIZE
if(strncmp(rcv_buffer, "MATSIZE", 7) == 0)
{
Serial.println(rcv_buffer);
// GET CLUSTER SIZE
cluster_size_x = (rcv_buffer[8] + 1) - '0';
cluster_size_y = (rcv_buffer[10] + 1) - '0';
rcv_buffer[0] = 0; // CLEAR BUFFER
// PUBLISH NEW CLUSTER SIZE
char clust_size[20];
char clust_y[10];
itoa(cluster_size_x*10, clust_size, 10);
int i_0 = strlen(clust_size);
clust_size[i_0] = 'x';
clust_size[i_0+1] = 0;
itoa(cluster_size_y*10, clust_y, 10);
strcat(clust_size, clust_y);
client.publish(topic_size, clust_size);
}
}
\ No newline at end of file