Note for this project there are two programs: LDR_ESP_NOW for reading the LDR sensors and sending the train status via ESP_NOW, and 2. ESP_NOW_WiFi to receive the ESP_NOW information and use WiFi to transfer the status to a smart device.
///LDR_ESP_NOW.ino Client file#include "LDR_ESP_NOW.h";
uint8_t broadcastAddress[6] = {0xBC, 0xDD, 0xC2, 0xBA, 0xF3, 0x7F};uint8_t board_number = 2;
#define TESTING 0
LDR_ESP_NOW train; //no parenthesis
enum where_is_train train_loc;
void setup() { //so that we know what has been programmed Serial.begin(115200); Serial.println("LDR_ESP_NOW - reads LDRs and Tx status vis ESP_NOW"); train.begin(broadcastAddress); //defaults to 1,1,4 for signals }
void loop() {#if TESTING //test - send a message once a second static long fire_esp; static int count; if (millis( )> fire_esp + 1000) { count++; count = (count)&15; train.send_status(board_number*16+count); fire_esp = millis( ); Serial.println(board_number*16+count); //testing only } #else static where_is_train save_loc = startup ; where_is_train train_loc = train.monitor_train(); //parameter = 1 for testing without LDR if (train_loc != save_loc) { save_loc = train_loc; Serial.println(train_loc); //testing only train.send_status(board_number*16+train_loc ); } #endif }-----------------------------//Implementation file LDR_ESP_NOW.cpp#include "LDR_ESP_NOW.h"
#include <ESP8266WiFi.h>#include <espnow.h>
uint8 mac_addr[6];
//enum where_is_train train_loc;
// Callback when data is sentvoid OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { if (sendStatus == 0){ Serial.println("Delivery success"); } else{ Serial.println("Delivery fail"); }}
LDR_ESP_NOW::LDR_ESP_NOW ( ) : LDR_Ser_Sig3_Ser_Class ( ) { }
void LDR_ESP_NOW::begin (uint8_t mac[6] ) { int i; Serial.println(); for (i=0; i<6; i++) { mac_addr[i] = mac[i]; Serial.println(mac_addr[i], HEX); } Serial.println("------");LDR_Ser_Sig3_Ser_Class::begin(1,1,4); //- external NOR gate, +ve logic 4 signalsthe_train = startup;//set up as a WiFi stationWiFi.mode(WIFI_STA);
// Initialise ESP-NOW if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; }
// Once ESPNow is successfully Init, we will register for Send Call back to // get the status of Transmitted packet esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); esp_now_register_send_cb(OnDataSent); // Register peer esp_now_add_peer(mac_addr, ESP_NOW_ROLE_SLAVE, 1, NULL, 0); }
void LDR_ESP_NOW::send_status(uint8_t train_loc ){ esp_now_send(mac_addr, (uint8_t*)&train_loc, sizeof(train_loc));}
//tests for next state - no other action//returns next state. enum where_is_train LDR_ESP_NOW::train_state(int s0, int s1, int s2, int s3){
switch (the_train) {case startup : the_train = waiting; break; //alwayscase waiting : if (s0) the_train = coming0; if (s3) the_train = coming1; break;case coming0 : if (!s0) the_train = approaching0; break;case approaching0 : if (s1)the_train = arriving0; break; case arriving0 : if (!s1)the_train = station0; break;case station0 : if (s2) the_train = departing0; break; case departing0 : if (!s2) the_train = leaving0; break;case leaving0 : if (s3)the_train = going0; break; case going0 : if (!s3) the_train = waiting; break;case coming1 : if (!s3) the_train = approaching1; break;case approaching1 : if (s2)the_train = arriving1; break; case arriving1 : if (!s2)the_train = station1; break;case station1 : if (s1) the_train = departing1; break; case departing1 : if (!s1) the_train = leaving1; break;case leaving1 : if (s0)the_train = going1; break; case going1 : if (!s0) the_train = waiting; break;}return the_train;}
enum where_is_train LDR_ESP_NOW::monitor_train(uint8_t test ) {//parameter test added to allow shorting sensor to ground for train detected int s0 = train_over_sensor(COMING_SEN); //shorthand for sensorsint s1 = train_over_sensor(ARRIVE_SEN);int s2 = train_over_sensor(DEPART_SEN);int s3 = train_over_sensor(GOING_SEN);if (test) { s0 =!s0; s1=!s1; s2=!s2; s3=!s3;}signal_control(COMING_SIG,s0); //control signals signal_control(ARRIVE_SIG,s1); //RED then AMBER - GREEN signal_control(DEPART_SIG,s2); signal_control(GOING_SIG,s3); return train_state(s0,s1,s2,s3); //find next state}----------------------------//Header file: LDR_ESP_NOW.h#ifndef LDR_ESP_NOW_H#define LDR_ESP_NOW_H#include "Arduino.h"#include <LDR_Ser_Sig3_Ser_Class.h>
#define COMING_SEN 0 #define ARRIVE_SEN 1#define DEPART_SEN 5#define GOING_SEN 4#define COMING_SIG 0#define ARRIVE_SIG 1#define DEPART_SIG 2#define GOING_SIG 3
enum where_is_train {startup,waiting,coming0,approaching0,arriving0,station0,departing0,leaving0,going0, coming1,approaching1,arriving1,station1,departing1,leaving1,going1};
class LDR_ESP_NOW : public LDR_Ser_Sig3_Ser_Class { public : LDR_ESP_NOW ( ); //use default values for pins void begin(uint8_t mac_addr[6] ); //use default values for signals enum where_is_train monitor_train(uint8_t test = 0 ); void send_status(uint8_t loc ); private : enum where_is_train train_state(int s0, int s1, int s2, int s3); enum where_is_train the_train; }; //semi colon important#endif;------------------------------------------------------// Client file ESP_NOW_WiFi.ino --LCD added January 2023
// Client file ESP_NOW_WiFi.ino#include "ESP_NOW_WiFi.h"/*This program will receive model train information from an ESP_NOW talker * and generate an HTML file that may be read by a smart device. */
const char* ssid = "Monitor_Trains";const char* password = "12345678";
ESP_NOW_WiFi trains; //no parenthesis#include <LCD_1602.h>LCD_1602 lcd;
void setup() { Serial.begin(115200); Serial.println("ESP_NOW_WiFi Code"); trains.begin(ssid,password ); lcd.begin( ); lcd.message(0,"--ESP_NOW_WiFi--"); lcd.message(1,"-Monitor Trains-"); delay(1000); } void lcd_message(int loc){ if (loc/16 == 1) lcd.message(0,"Malanda "); if (loc/16== 2) lcd.message(1,"Jaggan "); lcd.message(loc&15); }
void loop ( ){ // trains.WiFi_message("No trains present."); static char train_mess[200], mal_mess[40], jg_mess[40], pos_mess[40]; static int save_loc; int train_loc = trains.monitor_train(); if (train_loc != save_loc) { save_loc = train_loc; Serial.println(train_loc); lcd_message(train_loc); switch (train_loc&15){ case waiting : strcpy(pos_mess,"No trains present."); break; case coming0 : strcpy(pos_mess,"Train coming from Tolga."); break; case approaching0 : strcpy(pos_mess,"Train approaching from Tolga."); break; case arriving0 : strcpy(pos_mess,"Train arriving from Tolga."); break; case station0 : strcpy(pos_mess,"Train from Tolga in Station."); break; case departing0 : strcpy(pos_mess,"Train departing for Miller."); break; case leaving0 : strcpy(pos_mess,"Train leaving for Miller."); break; case going0 : strcpy(pos_mess,"Train going to Miller."); break; case coming1 : strcpy(pos_mess,"Train coming from Miller."); break; case approaching1 : strcpy(pos_mess,"Train approaching from Miller."); break; case arriving1 : strcpy(pos_mess,"Train arriving from Miller."); break; case station1 : strcpy(pos_mess,"Train from Miller in Station."); break; case departing1 : strcpy(pos_mess,"Train departing for Tolga."); break; case leaving1 : strcpy(pos_mess,"Train leaving for Tolga."); break; case going1 : strcpy(pos_mess,"Train going to Tolga."); break; default : strcpy(pos_mess,"Train is lost!"); } strcpy(train_mess, "Malanda: "); if (train_loc/16 ==1) strcpy(mal_mess, pos_mess); strcat(train_mess,mal_mess); strcat(train_mess,"<P>Jaggan: "); if (train_loc/16 ==2) strcpy(jg_mess, pos_mess); strcat(train_mess,jg_mess); trains.WiFi_message(train_mess); // trains.WiFi_message("Malanda"); }}
}----------------------------------------------------//Implementation file ESP_NOW_WiFi.cpp#include "ESP_NOW_WiFi.h"#include "index.h"
#include <ESP8266WiFi.h>#include <espnow.h>
#include <ESPAsyncTCP.h>#include <ESPAsyncWebServer.h>// Create AsyncWebServer object on port 80AsyncWebServer server(80);
// Create an Event Source on /eventsAsyncEventSource events("/events");
ESP_NOW_WiFi :: ESP_NOW_WiFi ( ) { }// Callback function that is executed when data is received
int train_position;
void OnDataRecv(uint8_t * mac, uint8_t *train_status, uint8_t len) { Serial.println("CallBack"); for (int i = 0; i<6 ; i++){ Serial.print(mac[i]); if (i<5) Serial.print(':'); } Serial.print("\nBytes received: "); Serial.println(len); Serial.println(*train_status); train_position = *train_status;}
int ESP_NOW_WiFi::monitor_train( ){ return train_position;}
void ESP_NOW_WiFi:: begin(const char* ssid, const char* password ) { // Initialize Serial Monitor Serial.begin(115200); // Set device as a Wi-Fi AP+Station// WiFi.mode(WIFI_STA); WiFi.mode(WIFI_AP_STA); WiFi.softAP(ssid, password); // Handle Web Server server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/html", WiFi_Mess); }); // Handle Web Server Events events.onConnect([](AsyncEventSourceClient *client){ // send event with message "hello!", id and current millis // and set reconnect delay to 1 second client->send("hello!", NULL, millis(), 1000); }); server.addHandler(&events); server.begin( ); // Initialise ESP-NOW if (esp_now_init()) { Serial.println("Error initialising ESP-NOW"); return; } else Serial.println("\nESP-NOW Initialised\n"); // Set up receiver CallBack/Interrupt to get sent information esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); esp_now_register_recv_cb(OnDataRecv); }void ESP_NOW_WiFi::WiFi_message(char* mess){ events.send(mess,"train_state"); }----------------------------------//Header file ESP_NOW_WiFi.h#ifndef ESP_NOW_WiFi_H#define ESP_NOW_WiFi_H#include "Arduino.h"//#include <LDR_Ser_Sig3_Ser_Class.h>
enum where_is_train {startup,waiting,coming0,approaching0,arriving0,station0,departing0,leaving0,going0, coming1,approaching1,arriving1,station1,departing1,leaving1,going1};
class ESP_NOW_WiFi { public : ESP_NOW_WiFi ( ); void begin(const char* ssid, const char* password); void WiFi_message(char* mess); int monitor_train( ); }; //semi colon important#endif;--------------------------------------//index.h const char WiFi_Mess [] PROGMEM = R"(<!DOCTYPE html><HTML> <HEAD> <TITLE>Monitor Trains</TITLE> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <style> html { font-family: Arial; text-align: center; } body { max-width: 400px; margin:0px auto; } </style> </HEAD><BODY><H2>Monitor Trains.</H2><span id="train">Monitoring Trains!</span>
<script>if (!!window.EventSource) { var source = new EventSource('/events'); source.addEventListener('open', function(e) { console.log("Events Connected"); }, false); source.addEventListener('error', function(e) { if (e.target.readyState != EventSource.OPEN) { console.log("Events Disconnected"); } }, false); source.addEventListener('train_state', function(e) { console.log("train_state", e.data); document.getElementById("train").innerHTML = e.data; }, false);}</script> </BODY></HTML>)";-----------------------------