This project will enhance an earlier project DSP_Train_State and will use an ESP-13 to display the train state on a Smartphone/computer.
End product: Display on a PC
Source Code for this project.
Abstract/Summary: This project will enhance an earlier project that used LDRs to monitor the location of a train and control signals. This project uses an ESP13 to display the train state over WiFi.
Possible Audience: The target audience for this project are enthusiasts who wish to combine the two projects Dsp_Train_State and MESS_2_ESP_AP into one application that both controls the train signals but also sends the train status over WiFi. It is not suitable for readers who are just starting from scratch.
Keywords: Arduino UNO, Arduino IDE, Serial Monitor, C++ Classes, C++ libraries, HTML GET, Set State Identifier ssid, password, IP Address
Required Hardware: The project was developed using an Arduino UNO (Jaycar part XC4410), an ESP13 WiFi shield (Jaycar part XC4614). For convenience an Arduino prototyping board with screw terminals (Jaycar part XC3890) was used. Four LDRs and 4 signals or combinations of RED, AMBER and GREEN leds are required.
Required Libraries: Dsp_Train_State and MESS_2_ESP_AP. Since Dsp_Train_State uses two libraries LDR_Sensor_Class and LDR_Sensor_RAG it will be necessary to have copies of these.
This project is based on two projects Dsp_Train_State and MESS_2_ESP_AP.
1. Dsp_Train_State (Display the Train State) uses 4 LDR sensors to monitor the train position along a section of model railway track. The results are used to control 4 sets of railway signals through a RED-AMBER-GREEN sequence and to send the train location to the Arduino IDE Serial Monitor.
2. MESS_2_ESP_AP (Message to ESP13 Access Point) upon request sends messages from the micro-controller to the ESP13 shield that acts as a WiFi access point. The messages are received by a smartphone or other receiving device(s). The photo shows the ESP-13 WiFi shield. For convenience in wiring the output signals and input sensors a prototyping board with screw terminals is used.
There are two possibilities to merge the two projects:
i. The Dsp_Train_State could be treated as the base code with the MESS_2_ESP13_AP becoming the destination for the messages.
ii. The MESS_2_ESP_AP could be treated as the base code with the Dsp_Train_State being the source of the messages.
In this project the first option is chosen. The ESP13 will replace the Serial Monitor as the destination for the messages.
Since this project will merge the two projects Dsp_Train_State and MESS_2_ESP_AP it will be necessary to have the code, including libraries from these projects. Further since Dsp_Train_State used two libraries LDR_Sensor_Class and LDR_Sensor_RAG it will be necessary to have copies of these.
For readers who have worked through earlier projects and have the LDR_Sensor_Class, LDR_Sensor_RAG and MESS_2_ESP_AP libraries the procedure is quite simple:
1. load the code for Dsp_Train_State from the Programs Section and confirm that it still compiles and runs
2. save the file with the new name/label Dsp_State_ESP13
For readers "joining in" they will need to generate the libraries LDR_Sensor_Class, LDR_Sensor_RAG and MESS_2_ESP_AP on their own development platforms. Since the libraries are not available in *.zip format it will be necessary to regenerate the *.zip files
1. In the Arduino IDE create a new file LDR_Sensor_Class and from the page LDR_Sensor_Class_ code copy/paste the LDR_Sensor_Class.ino code.
2. Use the inverted triangle on the Arduino IDE and select "new_tab" and create two new files LDR_Sensor_Class.cpp and LDR_Sensor_Class.h
3. Copy/paste the code LDR_Sensor_Class.cpp and LDR_Sensor_Class.h and verify that the code will compile. (Any errors are probably due to embedded formatting characters in the text. These will need to be removed.)
4. Use a program such as Windows Explorer to create a *.zip file containing the *.cpp and *.h files
5. In the Arduino IDE select sketch-->Include Library-->Add *.zip library and select LDR_Sensor_Class.zip
6.Repeat for the LDR_Sensor_RAG class and MESS_2_ESP_AP
7. load the code for Dsp_Train_State from the Programs Section and confirm that it still compiles and runs
8. save the file with the new name/label Dsp_State_ESP13. Confirm it still compiles and runs
Without any LDRs I was able to satisfy myself with the operation by grounding the pins A0 to A3 in turn. (The initialisation code for the sensor enables the internal pull up resistor which is equivalent to a train above the sensor.)
After loading the Dsp_Train_State code and renaming as Dsp_State_ESP13 the part "new" code becomes:
In the code 4 objects signal0 ..signal3 of class LDR_Signals_RAG are created. (RAG = Red, Amber, Green)
Since the serial monitor will not be used the Serial.begin( ) can be commented out.
In the main loop every time the train state changed a message was displayed so this part of the code can be replaced with the WiFi request. The response routine will need to be modified as the message is being sent to the WiFi.
As a first step it is probably a good idea to run the code for MESS_2_ESP_AP to ensure the system including the smartphone all work. (Recall the switches on the ESP-13 shield will need to be set for programming and then ON to run the program. Its probably a good idea to reset the Arduino.)
Then
1. In the new program Dsp_State_ESP13 include the library MESS_2_ESP_AP. Use sketch-->include library --> and select MESS_2_ESP_AP from contributed libraries.
2. Create an object of the class MESS_2_ESP_AP: I have given it the label Train_State.
3. The MESS_2_ESP_AP class has three begin options (overloading). begin (ssid); begin (ssid, password); begin(ssid, password,ip_address). I have chosen to define all parameters. The first few lines of the Dsp_State_ESP13 will become:
4. The set up routine now needs to be modified to include the initialisation of the new object Train_State. ie
The diagram shows the definitions of positive and negative signals. Positive signals are pulled high to activate, negative signals are pulled low. The example code uses positive polarity signals.
Aside from the begin( ) method the MESS_2_ESP_AP (Message to the ESP shield Access Point) has two public methods.
1. MESS_2_ESP_AP::request( ) that returns a byte pointing to the memory location containing the WiFi received message.
2. MESS_2_ESP_AP::response(Mess) that sends the message pointed to by the argument. This method assumes the message is in Flash memory not dynamic or RAM memory.
Once the smartphone finds the WiFi access point - in this example DSP_State_ESP13 - the operator can connect by giving the ip address 192.168.4.27.
The diagram illustrates the sequence of events when the operator requests the browser connects to 192.168.4.27
1. The smartphone/client sends a HTML string that contains a "GET/ "command. The library MESS_2_ESP_AP has extracted the command. MESS_2_ESP_AP::request( ) points to that command.
2. The initial command will be a null message.
3. The server will respond with an HTML file. For this project the response includes an "update" tag
4. The response displays the {update} on the smartphone.
5. The next request from the client will contain the "GET/update" request.
6. The server now sends a different message depending up the train status.
Note the library MESS_2_ESP_AP::response( ) will add all the necessary HTML header and trailer code. Our project Dsp_State_ESP13 need only supply the different messages.
The modified code in the loop( ) will be:
void loop() {static where_is_train last_state = vacant2;int s0 = signal0.train_over_sensor( );int s1 = signal1.train_over_sensor( );int s2 = signal2.train_over_sensor( );int s3 = signal3.train_over_sensor( );the_train = train(s0,s1,s2,s3);char * theRequest = Train_State.request( );if (theRequest){ if (* theRequest =='\0') Train_State.response(MESS_2_ESP_Mess);else if (!strcmp(theRequest,"update.htm")) display_message(the_train);} }The text of message MESS_2_ESP_Mess and the example messages should be modified to more closely match this project. The method display_message( ) will also modify the sample code.
Possible new code will be:
const char MESS_2_ESP_Mess[] PROGMEM = { "Program Dsp_State_ESP13.""<br>Click to <a href=\"update.htm\">Continue</a>"};1. I have chosen to display the file name Dsp_State_ESP13. Other messages such as "Where's the train?" could be given
2. The "<br>" generates a break or new line on the browser (smartphone)
3. The HTML tag "<a href=\"update.htm\">Continue</a>" when "Continue" is pressed the browser generate an HTML request. Note the back-slash quote indicates we really want the quote in the message - otherwise the quote would terminate the message.
4. Since the message will not change, the directive PROGMEM tells the compiler not to place a copy of the message in dynamic memory/RAM. The included library MESS_2_ESP_AP assumes all the messages are in ROM/Flash memory.
If the else line is commented out (for now) a browser should connect and the ESP respond with the message.
The next step is to handle the update requests.
The initial message to the browser will include the command Click to <a href=\"update.htm\">Continue</a>.
Clicking on "Continue" the browser will send a message to the ESP13 that will include:
...........................GET/update.htm..................................
The library returns a pointer to the GET command. In this case "update.htm"
void loop() {......................char * theRequest = Train_State.request( );if (theRequest){ if (* theRequest =='\0') Train_State.response(MESS_2_ESP_Mess);else if (!strcmp(theRequest,"update.htm")) display_message(the_train);} }To handle the "update.htm" a routine display_message( ) is required where the argument is the state of the train.
display_message( ) will point the code to the various messages to displayed.
The messages in the sample code can be modified:
Note it was considered after the first message that included Click to Continue this message was no longer necessary and the tags were placed around the messages.
The model train layout is still in the prototyping phase. Photo shows a LDR between the rails and prototype signal using LEDs
The Arduino does not have great debugging facilities and what is happening over the WiFi can appear like magic. However the Tx serial line that sends commands to the ESP13 also goes to the Arduino IDE Serial Monitor and can be used to verify what is being sent to the ESP13. A sample listing is given below:
Most of the above code is generate by the library. The code at 27 seconds (8 lines) was part of the begin( ) while code at 42 seconds was the response. The 238 is the length of the message that includes our contribution "<a href="update.htm">Train coming</a>".
If the code only reaches the first "AT" it probably indicates the switches on the ESP13 have been left in the programming mode.
Also in the implementation of the library if the initialisation does not respond the on board LED on the Arduino is programmed to flash. Once again if this happens check the programming switches and reset the Arduino.
The final product was tested using two smartphones. One was rescued from the recyclable bin at the local library and seemed to be overloaded with hidden applications as the response to a command was anywhere from immediate to 25 seconds. Not an ideal test instrument as its desirable to get a response immediately a change is made.
As noted earlier on the bench some of the various responses can be tested by grounding inputs A0 through A3 in turn. (Inputs A0-A3 have been programmed high by default). Since the initial code only tests for A0 high this corresponds to a train over A0 or the state train coming. Grounding A0 corresponds to the train having passed A0. But since A1 is high the state will be "arriving" . Similarly grounding A1 the train will slip to state "departing" etc. Without actual LDRs intermediate states are missed but developers can be confident that they have a working system.
Since my layout is so small this is just a fun project. However it could be useful on a larger layout as my experiments found I could monitor the train from across the street outside my home.