利用painlessmesh的WiFi mesh的功能, 在一個mash的網路裡. 由一個ESP32(main Node)搭配Xbox Joystick傳送Json格式的指令, 去控制網絡中另一個Node(ESP32 with RelayBoard)的relay動作.
Using the WiFi mesh function of painlessmesh, in a mash network, an ESP32 (main Node) and Xbox Joystick transmit commands in JSON format to control the relay action of another Node (ESP32 with RelayBoard) in the network.
Architecture:
架構說明:
Xbox左邊搖桿向左切傳輸RELAY4_ON指令, 向下切傳輸RELAY1_ON指令, 向右切傳輸RELAY2_ON指令, 向上切傳輸RELAY3_ON指令, 按下ButtonX傳輸RELAY4_OFF指令, 按下ButtonA傳輸RELAY1_OFF指令, 按下ButtonB傳輸RELAY2_OFF指令, 按下ButtonY傳輸RELAY3_OFF指令.
Move the Xbox left joystick to the left to transmit the RELAY4_ON command, move it downward to transmit the RELAY1_ON command, move it to the right to transmit the RELAY2_ON command, move it upward to transmit the RELAY3_ON command then press ButtonX to transmit the RELAY4_OFF command, press ButtonA to transmit the RELAY1_OFF command, and press ButtonB to transmit the RELAY2_OFF command. , press ButtonY to transmit the RELAY3_OFF command.
Previous article:
Circuit:
圖一: Node10 Circuit
圖二: Node11 circuit
YouTube Demo:
ESP32 Main Node10 Joystick Code:
#include "painlessMesh.h"
//#include <ArduinoJson.h>
#include <Arduino_JSON.h>
#include <ezButton.h>
//-----Global variable---------------------------------------
#define LED_BUILTIN 2
//--------joystick------------------------------------------
#define VRX_PIN_L 33 // ESP32 pin GPIO33 (ADC0)
#define VRY_PIN_L 32 // ESP32 pin GPIO32 (ADC0)
#define VRX_PIN_R 35 // ESP32 pin GPIO33 (ADC0)
#define VRY_PIN_R 34 // ESP32 pin GPIO32 (ADC0)
#define SW_X 18
#define SW_Y 16
#define SW_A 17
#define SW_B 19
#define LEFT_THRESHOLD_L 2200
#define RIGHT_THRESHOLD_L 900
#define UP_THRESHOLD_L 2200
#define DOWN_THRESHOLD_L 900
#define LEFT_THRESHOLD_R 2200
#define RIGHT_THRESHOLD_R 900
#define UP_THRESHOLD_R 2200
#define DOWN_THRESHOLD_R 900
#define COMMAND_NO_L 0x00
#define COMMAND_LEFT_L 0x01
#define COMMAND_RIGHT_L 0x02
#define COMMAND_UP_L 0x04
#define COMMAND_DOWN_L 0x08
#define COMMAND_NO_R 0x00
#define COMMAND_LEFT_R 0x01
#define COMMAND_RIGHT_R 0x02
#define COMMAND_UP_R 0x04
#define COMMAND_DOWN_R 0x08
int valueX_L = 0 ; // to store the X-axis value
int valueY_L = 0 ; // to store the Y-axis value
int command_L = COMMAND_NO_R;
int valueX_R = 0 ; // to store the X-axis value
int valueY_R = 0 ; // to store the Y-axis value
int command_R = COMMAND_NO_R;
//----------------------------------------------
int bValue_A = 0; // To store value of the button
int bValue_B = 0; // To store value of the button
int bValue_X = 0; // To store value of the button
int bValue_Y = 0; // To store value of the button
ezButton buttonA(SW_A);
ezButton buttonB(SW_B);
ezButton buttonX(SW_X);
ezButton buttonY(SW_Y);
//-----------painlessmesh------------------------------------
#define MESH_PREFIX "Peter1015"
#define MESH_PASSWORD "No18141814"
#define MESH_PORT 5555
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
//Number for this node
int nodeNumber = 10;
void sendMessage() ;
String readings;
String getReadings();
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
//--------------------Json data ------------------------------
StaticJsonDocument<200> json_doc;
char json_output[100];
DeserializationError json_error;
const char* payload_node;
const char* payload_function;
const char* payload_data;
//------------------------------------------------------------
//char line[16];
//--------- Flag structure --------------------------------------
#define LINE_BUFFER_LENGTH 1024
typedef struct _vFlag
{
uint8_t LEDFlag=0;
uint8_t BTFlag=0;
uint8_t FunctionFlag=1;
uint8_t SendFlag=0;
}vFlag;
vFlag *flag_Ptr;
vFlag flag;
//--------- uart structure --------------------------------------
//----------uart--------------
#define LINE_BUFFER_LENGTH 64
typedef struct _vUart
{
char c;
int lineIndex = 0;
int line1Index = 0;
int BTlineIndex = 0;
bool lineIsComment;
bool lineSemiColon;
char line[128];
char BTline[20];
String inputString;
String BTinputString;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//-------------------------------------
TaskHandle_t hled;
TaskHandle_t huart;
void vLEDFlashTask(void *pvParameters);
void vUARTTask(void *pvParameters);
void initial()
{
Serial.println(F("Create Task"));
//----------------------------------------------------------------------
// Now set up two tasks to run independently.
xTaskCreatePinnedToCore(
vLEDFlashTask, "LEDTask" // A name just for humans
,
1024 // This stack size can be checked & adjusted by reading the Stack Highwater
,
NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
,
&hled //handle
,
0);
xTaskCreatePinnedToCore(
vUARTTask, "UARTTask" // A name just for humans
,
1024 // This stack size can be checked & adjusted by reading the Stack Highwater
,
NULL, 3 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
,
&huart //handle
,
0);
//----------------------------------------------------------------------
}
String getReadings()
{
JSONVar jsonReadings;
//Serial.print(F("meshTask at core:"));
//Serial.println(xPortGetCoreID());
jsonReadings["node"] = nodeNumber;
//jsonReadings["node"] = String(normAccel.XAxis);
//jsonReadings["node ID"] = String(mesh.getNodeId());
if(flag.FunctionFlag==1)
{
jsonReadings["function"] = "Joystick";
}
readings = JSON.stringify(jsonReadings);
return readings;
}
void sendMessage()
{
//String msg = "Hello from node 1 ";
String msg = getReadings();
//msg += mesh.getNodeId();
if(flag.SendFlag ==1)
{
msg=Uart.BTinputString;
Uart.BTinputString="";
flag.SendFlag=0;
}
mesh.sendBroadcast( msg );
taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 2 ));
}
void receivedCallback( uint32_t from, String &msg ) {
Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
flag.LEDFlag=1;
}
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
Serial.printf("Changed connections\n");
flag.LEDFlag=0;
}
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}
void setup() {
Serial.begin(9600);
/**240(default 240 160 80 40 20 and 10Mhz)***/
setCpuFrequencyMhz(160);
initial();
//-----------------------------------------------------------------
buttonA.setDebounceTime(50); // set debounce time to 50 milliseconds
buttonB.setDebounceTime(50); // set debounce time to 50 milliseconds
buttonX.setDebounceTime(50); // set debounce time to 50 milliseconds
buttonY.setDebounceTime(50); // set debounce time to 50 milliseconds
//------------------------------------------------
//-------------------------------------------------------------------
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
//-------------------------------------------
Serial.println(F("System On!"));
//-------------------------------------------
}
void loop()
{
Serial.print(F("Main at core:"));
Serial.println(xPortGetCoreID());
while (1)
{
buttonA.loop(); // MUST call the loop() function first
buttonB.loop(); // MUST call the loop() function first
buttonX.loop(); // MUST call the loop() function first
buttonY.loop(); // MUST call the loop() function first
// Read the button value
bValue_A = buttonA.getState();
bValue_B = buttonB.getState();
bValue_X = buttonX.getState();
bValue_Y = buttonY.getState();
if (buttonA.isPressed()) {
Serial.println("The buttonA is pressed");
Uart.BTinputString="{\"node\":10,\"ButtonA\":\"OFF\"}";
flag.SendFlag=1;
}
if (buttonA.isReleased()) {
Serial.println("The buttonA is released");
}
if (buttonB.isPressed()) {
Serial.println("The buttonB is pressed");
Uart.BTinputString="{\"node\":10,\"ButtonB\":\"OFF\"}";
flag.SendFlag=1;
}
if (buttonB.isReleased()) {
Serial.println("The buttonB is released");
// TODO do something here
}
if (buttonX.isPressed()) {
Serial.println("The buttonX is pressed");
Uart.BTinputString="{\"node\":10,\"ButtonX\":\"OFF\"}";
flag.SendFlag=1;
}
if (buttonX.isReleased()) {
Serial.println("The buttonX is released");
// TODO do something here
}
if (buttonY.isPressed()) {
Serial.println("The buttonY is pressed");
Uart.BTinputString="{\"node\":10,\"ButtonY\":\"OFF\"}";
flag.SendFlag=1;
}
if (buttonY.isReleased()) {
Serial.println("The buttonY is released");
// TODO do something here
}
//--------------------------------------------------------
valueX_L = analogRead(VRX_PIN_L);
valueY_L = analogRead(VRY_PIN_L);
valueX_R = analogRead(VRX_PIN_R);
valueY_R = analogRead(VRY_PIN_R);
// converts the analog value to commands
// reset commands
command_L = COMMAND_NO_L;
command_R = COMMAND_NO_R;
// check left/right commands
if (valueX_L > LEFT_THRESHOLD_L)
command_L = command_L | COMMAND_LEFT_L;
else if (valueX_L < RIGHT_THRESHOLD_L)
command_L = command_L | COMMAND_RIGHT_L;
// check up/down commands
if (valueY_L > UP_THRESHOLD_L)
command_L = command_L | COMMAND_UP_L;
else if (valueY_L < DOWN_THRESHOLD_L)
command_L = command_L | COMMAND_DOWN_L;
// print command to serial and process command
if (command_L & COMMAND_LEFT_L) {
Serial.println("COMMAND LEFT_L");
Uart.BTinputString="{\"node\":10,\"ButtonX\":\"ON\"}";
flag.SendFlag=1;
}
if (command_L & COMMAND_RIGHT_L) {
Serial.println("COMMAND RIGHT_L");
Uart.BTinputString="{\"node\":10,\"ButtonB\":\"ON\"}";
flag.SendFlag=1;
}
if (command_L & COMMAND_UP_L) {
Serial.println("COMMAND UP_L");
Uart.BTinputString="{\"node\":10,\"ButtonY\":\"ON\"}";
flag.SendFlag=1;
}
if (command_L & COMMAND_DOWN_L) {
Serial.println("COMMAND DOWN_L");
Uart.BTinputString="{\"node\":10,\"ButtonA\":\"ON\"}";
flag.SendFlag=1;
}
//-----------------------------------------------------
if (valueX_R > LEFT_THRESHOLD_R)
command_R = command_R | COMMAND_LEFT_R;
else if (valueX_R < RIGHT_THRESHOLD_R)
command_R = command_R | COMMAND_RIGHT_R;
// check up/down commands
if (valueY_R > UP_THRESHOLD_R)
command_R = command_R | COMMAND_UP_R;
else if (valueY_R < DOWN_THRESHOLD_R)
command_R = command_R | COMMAND_DOWN_R;
if (command_R & COMMAND_LEFT_R) {
Serial.println("COMMAND LEFT_R");
// TODO: add your task here
}
if (command_R & COMMAND_RIGHT_R) {
Serial.println("COMMAND RIGHT_R");
// TODO: add your task here
}
if (command_R & COMMAND_UP_R) {
Serial.println("COMMAND UP_R");
// TODO: add your task here
}
if (command_R & COMMAND_DOWN_R) {
Serial.println("COMMAND DOWN_R");
// TODO: add your task here
}
//-----------------------------------------------------
//-----------painlessmesh------------------------------
mesh.update();
}//----while(1)-------------------------------------------
}
//--------------------------------------------------------
/*--------------------------------------------------*/
void vLEDFlashTask(void *pvParameters) // This is a task.
{
(void)pvParameters;
Serial.print(F("LEDTask at core:"));
Serial.println(xPortGetCoreID());
pinMode(LED_BUILTIN, OUTPUT);
//oldMillis = millis();
for (;;) // A Task shall never return or exit.
{
if(flag.LEDFlag==1)
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay(200);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay(200);
}
else{
vTaskDelay(10);
}
}
}
//-------------------------------------------
void vUARTTask(void *pvParameters)
{
(void)pvParameters;
Serial.print(F("UARTTask at core:"));
Serial.println(xPortGetCoreID());
for (;;)
{
while (Serial.available() > 0)
{
Uart.c = Serial.read();
if ((Uart.c == '\n') || (Uart.c == '\r'))
{ // End of line reached
if (Uart.lineIndex > 0)
{ // Line is complete. Then execute!
Uart.line[Uart.lineIndex] = '\0'; // Terminate string
//Serial.println( F("Debug") );
//Serial.println( Uart.inputString );
processCommand(Uart.line); // do something with the command
Uart.lineIndex = 0;
Uart.inputString = "";
}
else
{
// Empty or comment line. Skip block.
}
Uart.lineIsComment = false;
Uart.lineSemiColon = false;
Serial.println(F("ok>"));
}
else
{
//Serial.println( c );
if ((Uart.lineIsComment) || (Uart.lineSemiColon))
{
if (Uart.c == ')')
Uart.lineIsComment = false; // End of comment. Resume line.
}
else
{
if (Uart.c == '/')
{ // Block delete not supported. Ignore character.
}
else if (Uart.c == '~')
{ // Enable comments flag and ignore all characters until ')' or EOL.
Uart.lineIsComment = true;
}
else if (Uart.c == ';')
{
Uart.lineSemiColon = true;
}
else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
{
Serial.println("ERROR - lineBuffer overflow");
Uart.lineIsComment = false;
Uart.lineSemiColon = false;
}
else if (Uart.c >= 'a' && Uart.c <= 'z')
{ // Upcase lowercase
Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
Uart.lineIndex = Uart.lineIndex + 1;
Uart.inputString += (char)(Uart.c - 'a' + 'A');
}
else
{
Uart.line[Uart.lineIndex] = Uart.c;
Uart.lineIndex = Uart.lineIndex + 1;
Uart.inputString += Uart.c;
}
}
}
} //while (Serial.available() > 0)
vTaskDelay(10);
}
}
//------------------------------------------------------------
void processCommand(char *data)
{
int len, xlen, ylen, zlen, alen;
char ctemp[20];
len = Uart.inputString.length();
if (strstr(data, "VER") != NULL)
{
Serial.println(F("W_ATE_Board_20231109"));
}
}
ESP32 Node11 Relay Code:
#include "painlessMesh.h"
#include <Arduino_JSON.h>
//-------------------------------------------------------------
#define MESH_PREFIX "Peter1015"
#define MESH_PASSWORD "No18141814"
#define MESH_PORT 5555
//-----Global variable---------------------------------------
#define LED_BUILTIN 2
//-----Relay------------------
#define RELAY1 15
#define RELAY2 13
#define RELAY3 32
#define RELAY4 33
//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
uint8_t LEDFlag=0;
uint8_t NodeFlag=0;
uint8_t FunctionFlag=1;
uint8_t SendFlag=0;
}vFlag;
vFlag *flag_Ptr;
vFlag flag;
typedef struct _vUart
{
String inputString;
String BTinputString;
} vUart;
vUart *Uart_Ptr;
vUart Uart;
//---------------------------------------------------
Scheduler userScheduler; // to control your personal task
painlessMesh mesh;
//Number for this node
int nodeNumber = 11;
// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain
String readings;
String getReadings();
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );
TaskHandle_t hled;
void vLEDFlashTask(void *pvParameters);
void initial()
{
Serial.println(F("Create Task"));
//----------------------------------------------------------------------
// Now set up two tasks to run independently.
xTaskCreatePinnedToCore(
vLEDFlashTask, "LEDTask" // A name just for humans
,
1024 // This stack size can be checked & adjusted by reading the Stack Highwater
,
NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
,
&hled //handle
,
0);
//----------------------------------------------------------------------
}
String getReadings()
{
JSONVar jsonReadings;
//Serial.print(F("meshTask at core:"));
//Serial.println(xPortGetCoreID());
jsonReadings["node"] = nodeNumber;
//jsonReadings["node"] = String(normAccel.XAxis);
//jsonReadings["node ID"] = String(mesh.getNodeId());
if(flag.FunctionFlag==1)
{
jsonReadings["function"] = "RelayBoard";
}
readings = JSON.stringify(jsonReadings);
return readings;
}
void sendMessage() {
String msg = getReadings();
//msg += mesh.getNodeId();
if(flag.SendFlag ==1)
{
msg=Uart.BTinputString;
Uart.BTinputString="";
flag.SendFlag=0;
}
mesh.sendBroadcast( msg );
taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 2 ));
}
// Needed for painless library
void receivedCallback( uint32_t from, String &msg )
{
JSONVar myObject = JSON.parse(msg.c_str());
if (myObject.hasOwnProperty("node")) {
//Serial.print("myObject[\"node\"] = ");
//Serial.println((int) myObject["node"]);
if((int) myObject["node"]==10)
{
flag.NodeFlag=1;
}
}
if (myObject.hasOwnProperty("function")) {
//Serial.print("myObject[\"function\"] = ");
//Serial.println((const char*) myObject["function"]);
}
if (myObject.hasOwnProperty("ButtonA")) {
if(flag.NodeFlag==1)
{
//Serial.print("myObject[\"ButtonA\"] = ");
//Serial.println((const char*) myObject["ButtonA"]);
String str=(const char*)myObject["ButtonA"];
if(str=="ON")
{
digitalWrite(RELAY1, LOW);
}
if(str=="OFF")
{
digitalWrite(RELAY1, HIGH);
}
}
}
if (myObject.hasOwnProperty("ButtonB")) {
if(flag.NodeFlag==1)
{
String str=(const char*)myObject["ButtonB"];
if(str=="ON")
{
digitalWrite(RELAY2, LOW);
}
if(str=="OFF")
{
digitalWrite(RELAY2, HIGH);
}
}
}
if (myObject.hasOwnProperty("ButtonY")) {
if(flag.NodeFlag==1)
{
String str=(const char*)myObject["ButtonY"];
if(str=="ON")
{
digitalWrite(RELAY3, LOW);
}
if(str=="OFF")
{
digitalWrite(RELAY3, HIGH);
}
}
}
if (myObject.hasOwnProperty("ButtonX")) {
if(flag.NodeFlag==1)
{
String str=(const char*)myObject["ButtonX"];
if(str=="ON")
{
digitalWrite(RELAY4, LOW);
}
if(str=="OFF")
{
digitalWrite(RELAY4, HIGH);
}
}
}
Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
flag.LEDFlag=1;
}
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}
void changedConnectionCallback() {
Serial.printf("Changed connections\n");
flag.LEDFlag=0;
}
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}
void setup() {
Serial.begin(9600);
setCpuFrequencyMhz(160);
initial();
//---------------------------------------------------
pinMode(RELAY1, OUTPUT);
digitalWrite(RELAY1, HIGH);
pinMode(RELAY2, OUTPUT);
digitalWrite(RELAY2, HIGH);
pinMode(RELAY3, OUTPUT);
digitalWrite(RELAY3, HIGH);
pinMode(RELAY4, OUTPUT);
digitalWrite(RELAY4, HIGH);
//---------------------------------------------------
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
}
void loop()
{
Serial.print(F("Main at core:"));
Serial.println(xPortGetCoreID());
while (1)
{
mesh.update();
}
}
/*--------------------------------------------------*/
void vLEDFlashTask(void *pvParameters) // This is a task.
{
(void)pvParameters;
Serial.print(F("LEDTask at core:"));
Serial.println(xPortGetCoreID());
pinMode(LED_BUILTIN, OUTPUT);
//oldMillis = millis();
for (;;) // A Task shall never return or exit.
{
if(flag.LEDFlag==1)
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay(200);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay(200);
}
else{
vTaskDelay(10);
}
}
}
//-------------------------------------------
沒有留言:
張貼留言