Last Updated: 20/01/2025

nowRail

Projects >> nowRail

Latest News

20/01/2025 nowRail v1.2.1 released.

Adds loco consisting functions for hand controllers and mods for NCE Cab Bus interaction.
Loco data TX and RX functions added to allow the sending of loco data between controllers.

20/01/2025 nowRail controller V2 with consisting released.

This version has loco consisting and the ability to transmit loco data between controllers

Contents

I have decided to do seperate tutorials for the different features. This will make it easier to add things as new features come along.

Click on the titles below to jump to the section.

I will try and add video tutorails to each section as I get time.

Introduction What is nowRail (Video tutorial)
Video Tutorials A list of all the nowRail video tutorials. (Video tutorial)
Getting Started What you need to get started and a tour of the sketch. (Video tutorial)
Download latest Version Download the latest nowRail sketch
Diagnostics Turns the diagnostic output to the Serial monitor on or off (Baud rate 115200);
Standard Pin Functions

Functions that add inputs and outputs that are directly connected to board pins.
These can be Buttons, Triggers, Sensors, Accessories or control panel LED's.
Limited in number by the useable board pins
Button Video tutorials

LED Video tutorial

SensorVideo tutorial

CD4021 Shift register Pin Functions

CD4021 Shift registers are a cheap way of adding as many INPUTpins as required.
These inputs can be Buttons, Triggers or Sensors that give a digital signal.
This allows for far more buttons or sensors than your board has pins for

Button Video tutorial

SensorVideo tutorial

GT911 Touch screen Functions Allows the integration of touch screens with GT911 controller chips for touch screen turnout control panels.
This allows the building of quite large touch control panels at a fraction of the price of a touch screen LCD.
74HC595N Shift register Pin Functions

74HC595N Shift registers are a cheap way of adding as many OUTPUT pins as required. This allows for far more solenoids, LED's etc than your board has pins for.
Solenoid/LED Video tutorial

Mimic panel LED Video tutorial

PCA9685 Servos Function to add and control a servo connected to PCA9685 servo driver board (Video tutorial)
PCA9685 Leds Function to add and control a leds connected to PCA9685 boards. Effect options are on/off, fire flicker, gas light, arc welder. (Video tutorial)

On/Off basic on or OFF led at bightness level set.
Fire flicker gives a more visable flicker giving random values between the highest and lowest brightness values.
Gas Light gives a far less visable flicker (less flickers and more subtle) between the highest and lowest values.
Arc Welder Gives a vigourous on off flicker to mimic and arc welder effect. Best run between maximum brightness and zero.
MASTERCLOCK MASTERCLOCK sets a board as the layout MASTERCLOCK that all other boards clocks will sync to.
MP3 Player Functions Version 1_0_0 introduces MP3 player control. Individual tracks can be played or a number of tracks can be played in a random sequence (Video tutorial)
Layout Time Functions Functions that interact with the nowRail layout time clock.
EEPROM EEPROM can be configured to store the layout time so that the system continues at the same point after power off.
When enabled time and loco settings are automatically saved with no user input.
JMRI How to connect directly to JMRI as a CMRI node (USB connection directly to ESP32 board.
Currently supports sensor data being passed to JMRI and Turnout and Lights commands beng passed to nowRail. (Video tutorial)
NCE Cab Bus connection How to set nowRail to pass DCC loco and Accessory commands to NCE Cab Bus (Video tutorial)
DCC EX connection How to set nowRail to pass DCC loco and Accessory commands to DCC EX (Video tutorial)
Loco and Accessory control functions Functions that send instructions to the system to control locos and accessories. Commands passed to DCC-EX if connected.
Loco Controller functions nowRail has an internal 200 loco roster array storing DCC Address, function states and loco name. These functions enable users to build their own controllers calling these built in functions.
Data is saved to EEPROM when EEPROM configured.
Touch screen Loco Controller This is an example build of a touch screen loco controller using nowRail.
Componenets are ESP32 Dev Module, Rotary Encoder Module, 10k Ohm resistor, 24LC256 EEPROM chip and 3.5" LCD touch screen (480 x 320) SPI version ILI9486 FT6236 or ILI9488 FT6236.(Video tutorial)
DCC Controller input A simple way to take Accessory commands from any DCC system and broadcast them over nowRail
Custom Functions How to get nowRail to trigger your own custom code
Button Debounce How to adjust the button debounce sensitivity
TURNOUTPULSE How to adjust the length of a pulse for solenoid type point motors.


nowRail - Introduction

What is nowRail?

nowRail is a communication protocol for model railways, both analogue and DCC.

The protocol uses ESP-NOW Broadcast mode, a form of wifi communication that runs without a wifi router as shown in the diagram below.



ESP-NOW broadcast mode

The system is able to connect Loco and Accessory decoders to Accessory and Animationscontrollers as well as being able to send loco commands to DCC-EX. It can also receive incoming commands from other DCC systems.

The original system for my own layout "The Isle of Mudd" worked well but had a limitation of conventional ESP-NOW (about 20 items) and also required some programming skills to add new items.

The nowRail version has been written in a way that makes it very easy (often with little or no coding) to add buttons, turnout controls and various other items.

IOM Railway Control

Hardware Requirements

Part of the goal of the project was to make the system as affordable as possible. As such the system has been built around ESP32 Dev Modules (about £6,50 on Amazon), ESP8266 D1 Mini boards ( 2 for £10) . The code has been tested on some other board but my focus has been on the two main types of board.

For inputs the system already has built in code for various types of buttons including the old stud and probe type system.

For turnout control the system has built in functions to use servos and solenoid type point motors.

The system also has a built in layout clock with adjustable speeds and has functions for triggering events based on layout time with built in code to store the current time to EEPROM for when the layout next starts up.

All the above functionality works on both analogue and DCC systems.

For those who want to connect to their DCC system there are a couple of options built in.

Commands for locos and accessory decoders can be passed to a DCC-EX system while a simple DCC decoder circuit allows the system to broadcast accessory decoder command from any DCC system.

How it works

This is a flow diagram of how the system works. Don't worry, you don't need to understand but it's for those who are interested.

Code Flow Diagram

Commands are created and transmitted, each command is prefixed with a layout code. This stops interferance from other layouts or other items broadcasting on an ESP-NOW system.

Each board receives all transmissions and looks through it's list of accessories/functions to check if it needs to do anything. This works in a similar way to DCC with units ignoring anything that doesn't have the units address.

Certain crucial messages will send a responce to say they have been received and if not the system will retransit at intervals up to 5 times.

For some items such as turnout controls a panel response message is also transmitted when the turnout/accessory has processed its command. The panel message is processed by control panels to change status indicators etc.

Due to the nature of the system multiple control panels can control the same items ( a number of people with their own control panel) but will all receive a panel update no matter which panel sent the command. This means all controllers/panels display the latest information.

As the system uses broadcast mode new controllers can be added or removed without having to change the configuration of any other panel or decoder.

Although I have tried to write a lot of very simple functions for those who are not used to coding such as:

myLayout.addPCA9685Servo(0x40,15,300, 10, 160); This line would add a servo on PCA9685 board 0x40 that responds to accessory address 300. If the direction is 0 the unit will move to 10 degrees, direction 1 would move to 160 degrees,

All control code incuding the PCA9685 driver board is included within nowRail so no libraries need to be manually added.

In the same way buttons are added with lines such as:

myLayout.addStdPinButton(26,100,0,0);//single press pin 26, accNum 100, always sends 0

and

myLayout.addStdPinButton(33,200,0,1);//single press pin 33, accNum 200, 0 1st press, 1 2nd press

All the debouncing, even the pinMode is taken care of internally.

The system has similar functions to add extra buttons using cheap 74HC595NP and CD4021 shift registers to allow almost limitel;ess nunmbers of digital inputs and outputs on the system.


As well as the simple ways of adding items there are also functions to allow the user to create their own custom routines. I have been working on a touch screen controller that works in that way.

Additional Resources for introduction

#70 ESP-NOW Broadcast Mode 06/03/2024

Random Nerds Getting Started with ESP-NOW (ESP32 with Arduino IDE)

Random Nerds Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)



The Software - The nowRail sketch

Updated 06/04/2024

The basic code contains 5 tabs.

The main sketch tab that is renamed to whatever you want the item to control.

A file called nowRail.cpp and nowRail.h that control the system. The code in these may look complicated but the good news is that users do not need to edit or even understand these files.

There is a new tab called customFunctions.ino This contains various functions that get called when various events happen to enable users to write their own custom driven code. These functions can be deleted if not required (most basic installations do not require them).

Finally there is nowrail_user_setup.h (in early versions this was called setup.h) that allows the user to turn on or off certain functions and features.

Version Changes
Future versions


Suggestions for future versions


Email me (link at bottom of page) for other additions/suggestions.

Current requests

Ability to put certain accessories under single user control

PCA9685 flashing LED on/off 1 per second



Current Stable Version
Version 1.2.1



Version 1.2.1


Additions

Mods to NCE Cab Bus: Ability to choose if loco addresses 1-128 will be sent as LONG or SHORT address congidured by: #define CAB_BUS_SHORTADDRON 0

2 Extra functions added to allow loco consisting to be added to controllers

locoGetConsistState
locoSetConsistState

 




Version 1.1.0



Version 1.1.0


Additions

Ability to control the speed of PCA9685 servos to enable slow speed turnout control

Version 1.0.1


Version 1.0.1


Additions

MP3 player intergration for DY-SV5W, DY-SV8F, DY-HV8F, DY_HV20T, JQ8900 using Serial2 connection. Requires ESP32 Dev Module or other ESP32 board with Serial 2 capability

Improvements

Serial2 for MP3, DCC EX and NCE Cab bus are now set up internally so no longer need to be configured in setup()

Bug Fixes

MP3 information now only displays when DIAGNOSTICS_ON

Version 0.9.1


Version 0.9.1


Additions

PCA9685 Leds control with various effects

Version 0.8.2


Version 0.8.2



Additions

NCE Cab bus intergration for Loco speed/function and turnout control


2 new functions have been added to customFunctions.ino

void nowLocoSpeedUpdate(int locoAddr, byte locoSpeed, byte locoDir);//allows custom code to be triggered by a loco speed command

void nowLocoFuncUpdate(int locoAddr, byte nowFuncNum, byte nowFuncState);//allows custom code to be triggered by a loco function command.

ESP-NOW in ESP32 board manager v2+ and v3+ compatible

Version 0.7.2


11/06/2024
Version 0.7.2

This version has had some major changes due to the changes to ESP-NOW in ESP32 board manager v3.0.0

This version works with the old version 2+ as well as the new version 3+

Additions
Extra custom functions for hand controller applications

void nowClockSpeedUpdate(void) Triggered when a clock speed change is broadcast, allows fats clocks on all controllers to update

void nowLocoFuncUpdate(int nowLocoID, byte nowFuncNum, byte nowFuncState) Triggered when a loco function is changed. Allows all controllers to update the functions in controller loco array.

nowrail_user_setup.h
The old user_setup.h file has been renamed to nowrail_user_setup.h to prevent conflicts with other libraries. The file contents remain the same

nowRail 0.7.2

WARNING
This version works with ESP32 2.0.17 or lower


Version 0.6.0

The latest ESP32 board library (3.0.0) has brought major changes to some of the library functions. I am currently working on the required upgrades.

13/05/2024

Version 0.6


Additions
Sensors added to nowRail

JMRI integration

Sensor data passes to JMRI, sensors can be connected to ESP32 board pins or via CD4021 shift register for extra pins.
Turnouts and Lights data is passed from JMRI to nowRAil via CMRI (direct USB connection).

Version 0.5.0

06/05/2024

Version 0.5


Additions
DCCDECODERPIN now works with a greater number of ESP32 boards.

Thanks to Joe Haydu for the testing

Version 0.4.1

27/04/2024

bug fix
Improved error handling in DCCDECODERPIN
Thanks to Joe Haydu for the testing




Additions

Mimic panel commands added.

addStdPanelLed(int pin,int accNum, int dir); //adds a mimic panel pin directly to processor board

74HC595N Shift register Pin Mimic panel LED functions //Functions that allow control mimic panel LED's to be added

Custom functions now moved to seperate tab to make setting up easier for new users.
Power Commands added PowerON, Power Off, Emergency Stop... sent automatically to DCC-EX when option selected
GT911 Touch screen integration
Loco Roster Data stored in EEPROM
Loco Roster function to call and set DCC Decoder Address, Function states, Loco Name

Version 0.3 01/04/2024
Improvements to 74HC595N Accessory functions.
Standard pin and standard 74HC595N panel pin functions added for control panel LED control
Improved shiftIn code.
Odd Serial.print() commands removed.

Version 0.2 Initial Beta Release.


Getting Started


Download the zip file from the links above.

Open it up in your IDE. I will be using the Arduino IDE v2.3 in Dark Theme mode for the screen shots.

In the first tab at the top of the page you will see these lines.

nowRail set up layout address.

For testing you can leave the line layout address as the default:

nowRail myLayout(0x00, 0x01, 0x02, 0x03)


As it is, however if you are using nowRail on a portable layout or have a neighbour using nowRail change the values 0x00, 0x01, 0x02, 0x03 to a set of values unique to your layout.

You can use HEX values from 0x00-0xFF or use decimal values 0-255. Look at them as your layouts pin number.
All messages transmitted will be prefixed with this code so your layout will ignore any traffic it picks up for other addresses.

Once you have done this resave the sketch.

This will be your default sketch that will be used for all control panels, accessory decoders and any other features. So you are now ready to build your first control system.

ESP32 boards with Arduino IDE

If you are using ESP32 boards for the first time you will need to load the ESP32 board library.

The library you need to load is esp32 by Expressif Systems

You will also need to add a line in your preferences. In Windows go to File> Preferences, at the bottom of the Windows you will see a line

Additional board Manager URL's: Enter the following in that box and click OK.

https://espressif.github.io/arduino-esp32/package_esp32_index.json

Function List

Standard Pin Functions (functions that use items connected firectly to the board pins) Items connected could be a button, stud and probe, sensor etc.

These functions are limited to the number of usable pins on your board.

This first video shows how to use the void addStdPinButton(int pin, int accNum, int press1, int press2); function.
void addStdPinButton(int pin, int accNum, int press1, int press2);

This connects a standard button to the board using a PULL_DOWN resistor.

int pin: The board pin the button is connected to.
int accNum: accNum is the accessory number you want the button to control.
int press1: The direction you want the button to send when pressed the firsdt time.
int press2: The direction you wish to be sent when the button is pressed a 2nd time.

Examples:

myLayout.addStdPinButton(15, 100, 0, 0);//pin 15 sends to accessory 100 a command of 0 every time the button is pressed. This would usually be paired with a second button that sent a 1 when pressed to send the opposite command.

myLayout.addStdPinButton(5, 200, 0, 1);//pin 5 sends to accessory 200 a command of 0 first press, 1 second press. This is used when you want the same button to be able to switch something on and off.

void addStdPinAcc(int pin, int accNum, int dir, int pulse, int setpinState);

This connects and standard digital output to a pin.
The digital output could be used to control a solenoid point motor (will require a relay or mosfet), or turn a buildings lights on/off.

int pin: The board pin the button is connected to.
int accNum: accNum is the accessory number you want the button to control.
int dir: The direction you want this function to respond to
int pulse: When set to 1 this will send a pulse signal (default is 0.5 seconds) for solenoid control. Setting the value to 0 leaves the output set to the desired output HIGH/LOW until it is reset from another source.
int setpinState: This is the signal pulse or constant state you want the pin set to. So if set to HIGH the pulse would be HIGH, then after 0.5 seonds would go LOW.
For non Pulse it would set the pin to the value HIGH or LOW

Examples:

Solenoid type point motor:

In this example pin15 triggers a pulse to one coil while pin 2 triggers the opposite direction

myLayout.addStdPinAcc(15,100,0,1,HIGH);//pin 15, acc 100, dir 0, PULSE,HIGH...Stall motor... relay or mosfet controlled

To move the solenoid the other direction would have a line such as

myLayout.addStdPinAcc(2,100,1,1,HIGH); //pin 2, acc 100, dir 1, PULSE,HIGH...Stall motor... relay or mosfet controlled

ON/OFF switch style control... building lights as an example

In this example both functions control the same pin.

When accessory 200, direction 0 is received the output is set HIGH and left high as pulse is set to 0.
When accessory 200, direction 1 is received it turns pin 4 low...turns it off.

myLayout.addStdPinAcc(4,200,0,0,HIGH);//pin 22, acc 200, dir 0, NO PULSE, HIGH...turns pin HIGH...switches ON

myLayout.addStdPinAcc(4,200,1,0,LOW);//pin 23, acc 200, dir 1, NO PULSE, LOW..on off switch, turns pin 4 LOW, switches off.



void addStdPanelLed(int pin, int accNum, int dir);

This connects and standard digital output to a pin specifically for displaying LED's on control panels.

It will respond to a panel command that is sent after a DCC accessory has processed a command.

The panel command informs nowRail that a command has been processed.

The LED will be turned on when the appropriate command is received and turned off if the opposite command is received.

int pin: The board pin the button is connected to.
int accNum: accNum is the accessory number you want the button to control.
int dir: The direction you want the panel LED to turn on with


Examples:

The example below would control 2 LED's to show the turnout durections on a control panel

myLayout.addStdPanelLed(15, 100, 1);;//pin 15, acc 100, will go HIGH when direction 1 is received and LOW when 0 received.






void addStdPinSensor(int pin, int senNum);

This connects and standard digital output to a sensor or any type

It will be polled at intervals set by SENSORDEBOUNCE 100 (defaults to 0.1 seconds) in user_setup.h

The sensor changed state will be broadcast with the results visible in the function
void nowSensorUpdate(int senNum, byte senInst) that can be found in customFunctions.ino with the ability for users to set up custom code to deal with the sensor being triggered.

If a board is connected to JMRI the sensor data will be transmitted to JMRI over a CMRI connection




int pin: The board pin the sensor is connected to.
int senNum: senNum is the sensor number, if using JMRI it is the sensor number without the node number (first digit).

JMRI sensor 1010 would be sensor 10 on node 1.


Examples:

myLayout.addStdPinSensor(15, 100,);;//pin 15, sensor number 100






 

MASTERCLOCK_ON

All boards have a clock system built in, however the MASTERCLOCK_ON means that the board in question will broadcast the time to all other boards at regular intervals to keep all boards in sync.
If you are using EEPROM to store clock times this is an ideal board to add the EEPROM to.

Ideally the board running as MASTERCLOCK_ON should always be on so I use the board that connects my layout to DCC EX as the trains won't run wothout it.

The following line must be uncommented in user_setup.h

#define MASTERCLOCK_ON //this board is the master clock and will send out a broadcast to sync all other boards

 

Time Functions nowRail has a built in layout time clock. Thes speed of the clock can be accelerated or stopped as required.
void sendClockSpeedChange(byte clockSpeed); This sets the speed of the layout clock. Accepted values are 0 (stopped) to 255 (255 seconds per real world second).


byte clockSpeed: The value between 0-255 that you want the clock speed set to.
Clock Outputs

These allow the user to update clocks on the layout both on control panels and layout display boards and can be called from custom code in the style

byte timeHours = myLayout.rtcHours(void);
byte rtcClockSpeed(void);


Returns a byte with the value of the current layout clock speed 0-255


byte rtcHours(void);


Returns a byte with the value of the current layout Hour 0-23


byte rtcMinutes(void);


Returns a byte with the value of the current layout minutes 0-59


byte rtcSeconds(void);


Returns a byte with the value of the current layout seconds 0-60


byte rtcDays(void);


Returns a byte with the value of the current layout day 0-6


 

CD4021 Shift register inputs

nowrail allows almost limitless amounts of digital inputs (buttons/sensors) to be added using CD4021 shift registers

See the tutorial at https://www.digitaltown.co.uk/71CD4021BEShiftRegister.php on how to use them

The system defaults to a maximum of 2 chips as defined by the line #define NUMCD4021CHIPS 2
Changing this value to a higher number will enable more chips to be daisy chained.

nowRail will configure it's arrays accordingly. Each chip adds an extra 8 inputs.

NOTE: In the circuit diagram the CD4021 chips and and buttons/sensors are being powered by the ESP32 3.3v output. If a large amount of items are added you may need to supply a seperate 3.3v power supply.

I have not added buttons to all the inputs.

nowRail treats the chip closest to the ESP32 as Chip 0.

Components

CD4021
ESP32 Dev Module

ESP32 with CD4021 Shift register

For more information on the CD4021 Shift register see the tutorial at CD4021B Shift Register

void setupCD4021(int latchPin, int clockPin, int dataPin);

This function is called in the setup() function after myLayout.init();

int latchPin: The board pin connected to the CD4021 latchPin
int clockPin: The board pin connected to the CD4021 clockPin
int dataPin: The board pin connected to the CD4021 dataPin

void addCD4021PinButton(int chip, int pin, int accNum, int press1, int press2);


Works in the same way as adding a standard pin. The only difference is the pin is the pin number on the chip and a chip number needs to be added with 0 being the chip closest to the processor board if multiple chips are being daisy chained,

These functions are added in the setup AFTER void setupCD4021(int latchPin, int clockPin, int dataPin);

int chip: The chip number the pin is on, 0 is closest to the ESP board o the daisy chain
int pin: The pin on the CD4021 that is being connected to
int accNum: The accessory address you want the button/input to control
int press1:Value sent 0/1 on first press
int Press2: Value sent 0/1 on 2nd press

NOTE: system defaults to 30 items (more thn one function can be called per pin). Chaning the value of the line #define NUMCD4021CHIPSNUMBUTTONS 30 to a higher number will enable more items to be added. nowRail will size it's arrays accordingly.

Examples:

myLayout.addCD4021PinButton(0,1,10,0,1);//chip zero, pin 1 will send an instruction to accessory number 10. The instruction will be 0 first press and 1 second press

myLayout.addCD4021PinButton(1,0,20,0,0);//chip 1, pin 0 will send an instruction to accessory 20 of 0 every time the button is pressed
myLayout.addCD4021PinButton(1,5,20,0,0);//chip 1, pin 5 will send an instruction to accessory 20 of 1 every time the button is pressed

Setup would look like:

myLayout.init();

myLayout.setupCD4021(12,13,15);
myLayout.addCD4021PinButton(0,1,10,0,1);
myLayout.addCD4021PinButton(1,0,20,0,0);
myLayout.addCD4021PinButton(1,5,20,0,0);


void addCD4021PinSensor(int chip, int pin, int senNum);


This function adds a sensor to a CD4021 shift register pin

It will be polled at intervals set by SENSORDEBOUNCE 100 (defaults to 0.1 seconds) in user_setup.h

The sensor changed state will be broadcast with the results visible in the function
void nowSensorUpdate(int senNum, byte senInst) that can be found in customFunctions.ino with the ability for users to set up custom code to deal with the sensor being triggered.

If a board is connected to JMRI the sensor data will be transmitted to JMRI over a CMRI connection

int chip: The chip number the pin is on, 0 is closest to the ESP board o the daisy chain
int pin: The board pin the sensor is connected to.
int senNum: senNum is the sensor number, if using JMRI it is the sensor number without the node number (first digit).

Setup would look like:

myLayout.init();

myLayout.setupCD4021(12, 14, 13);//set up the CD4021 chips
//add sensors to CD4021CHIPS
myLayout.addCD4021PinSensor(0, 0, 44);//chip 0, pin 0, sensor 44 myLayout.addCD4021PinSensor(0, 1, 43);//chip 0, pin 1, sensor 43

 

74HC595N Shift register ouputs nowrail allows almost limitless amounts of digital outputs for control of various items by using 74HC595N shift registers that are daisly chained.


The system defaults to a maximum of 2 chips as defined by the line #define NUM74HC595NCHIPS 2
Changing this value to a higher number will enable more chips to be daisy chained.

nowRail will configure it's arrays accordingly. Each chip adds an extra 8 outputs.

A typical circuit diagram is shown below. Although the outputs shown are connected to LED's, outputs could be connected to Mosfets, Transistors, Motor drivers and relays. Anything that accepts a digital output.

If using multiple 74HC595N The chip closest to the ESP32 is regarded as Chip 0 with daisy chained chips then being Chip 1, Chip2 etc

Components

74HC595N
ESP32 Dev Module

ESP32 with 74HC595 Shift Register

void setup74HC595N(int latchPin, int clockPin, int dataPin);

This function is called in the setup() function after myLayout.init();

int latchPin: The board pin connected to the 74HC595N latchPin
int clockPin: The board pin connected to the 74HC595N clockPin
int dataPin: The board pin connected to the 74HC595N dataPin

Example:
myLayout.setup74HC595N(14,16,2); //latchPin 14, clockPin 16, dataPin 2

void add74HC595NPinAcc(int chip, int pin, int accNum, int dir, int pulse, int setpinState);


Works in the same way as adding a standard pin. The only difference is the pin is the pin number on the chip and a chip number needs to be added with 0 being the chip closest to the processor board if multiple chips are being daisy chained,

These functions are added in the setup AFTERvoid setup74HC595N(int latchPin, int clockPin, int dataPin);

int chip: The chip number the pin is on, 0 is closest to the ESP board o the daisy chain
int pin: The pin on the 74HC595N that is being connected to
int accNum: The accessory address you want the button/input to control
int dir: The direction (0/1) that this pin should respond to.
int pulse:0 = Pins stays HIGH of LOW until next instruction. 1 = pin will pulse for 0.5 seconds
int setpinState: The state the pin should go to HIGH/LOW or should pulse

NOTE: system defaults to 2 x the number of chips defined in NUM74HC595NCHIPS.
This allows two function per pin so that items can be turned on and another function turn them off.

Examples:

myLayout.add74HC595NPinAcc(0, 0, 300, 0, 0, HIGH);//chip zero, pin 0 will respond to Accessory Address 300 and will set the pin HIGH
The same pin would be set LOW by the followsing
myLayout.add74HC595NPinAcc(0, 0, 300, 1, 0, LOW);

myLayout.add74HC595NPinAcc(1, 5, 100, 1, 1, HIGH);//chip 1, pin 5 will respond to a direction of 1 with a HIGH pulse

The following line would set the solenoid in the opposite direction with the opposing coild being driven by pin 4

myLayout.add74HC595NPinAcc(1, 4, 100, 0, 1, HIGH);//chip 1, pin 4 will respond to a direction of 0 with a HIGH pulse

Setup would look like:

myLayout.init();

myLayout.setup74HC595N(14,16,2);
myLayout.add74HC595NPinAcc(0, 0, 300, 0, 0, HIGH);
myLayout.add74HC595NPinAcc(0, 0, 300, 1, 0, LOW);
myLayout.add74HC595NPinAcc(1, 5, 100, 1, 1, HIGH);
myLayout.add74HC595NPinAcc(1, 4, 100, 0, 1, HIGH);



void add74HC595NPPanelLed(int chip,int pin,int accNum, int dir);

Works in the same way as adding a addStdPanelLed(int pin,int accNum, int dir);

These outputs are designed to be used specifically for mimic panel LED's to show track direction.

They respond to Panel Update commands that are sent after an Accessory command has been processed.

They go HIGH when the accNum and dir match the pin setup configuration and will go LOW if an accNum command is received for the opposte direction.

These functions are added in the setup AFTERvoid setup74HC595N(int latchPin, int clockPin, int dataPin);

int chip: The chip number the pin is on, 0 is closest to the ESP board o the daisy chain
int pin: The pin on the 74HC595N that is being connected to
int accNum: The accessory address you want the button/input to control
int dir: The direction (0/1) that this pin should respond to.


NOTE: system defaults to 2 x the number of chips defined in NUM74HC595NCHIPS.
This allows two function per pin so that items can be turned on and another function turn them off.

Examples:

myLayout.add74HC595NPPanelLed(1,4,300, 0);//chip zero, pin 4 will respond to Accessory Address 300 and will set the pin HIGH if dir = 0 and LOW if dir = 1


The opposite for a turnout would be:

myLayout.add74HC595NPPanelLed(1,5,300, 1);//chip zero, pin 5 will respond to Accessory Address 300 and will set the pin HIGH if dir = 1 and LOW if dir = 0



Setup would look like:

myLayout.init();

myLayout.setup74HC595N(14,16,2);
myLayout.add74HC595NPPanelLed(1,4,300, 0);
myLayout.add74HC595NPPanelLed(1,5,300, 1);



 

GT911 Touch Screen Function These functions allow users to intergrate touch screens with a GT911 controller



These types of screen are ideal for laying over neopixels or LED's to create touch screen mimic panels.
A lot seem to be designed for car sat nav systems.

I buy mine off AliExpress, click this link to view screens.
As you will find they come in a variety of sizes, make sure you pick GT911 versions.

You will also need a FPC/FFC Flexible Cable Adapter Board 0.5mm Pitch, make sure you get the 6 Pin 0.5mm spacing so that you can connect to your Arduino.

The pinout connections should be on the flexible ribbon cable as can just be seen in the photo below


GT911 Capacitive Touch Screen Arduino

Pin Connections:

GT911 Touch Screen ESP32 ( I have not tested on ESP8266 but it should work the same)
VCC 3.3v
Gnd Gnd
SDA SDA (GPIO 21 ESP32 dev module)
SCL SCL (GPIO 22 ESP32 dev module)
Reset Any suitable free pin (passed in void addGT911Screen(int GT911ResetPin,int GT911IntPin); )
Int Any suitable free pin (passed in void addGT911Screen(int GT911ResetPin,int GT911IntPin); )



Debounce is set by the value of #define BUTTONDEBOUNCE 250 in user_setup.h

In user_setup.h the following most be incommented

//GT911 Touch Screen

#define GT911 0x5D //Uncomment for gt911 touch screen

#define GT911TOUCHBUTTONS 30 //sets the max number of touch point buttons, increase for more buttons.

#define GT911TOUCHRADIUS 35 //35 is approx 5mm either side of the centre touch point, increase/decrease to suit preferences...finger size.

Also

#include "Wire.h"


For more information on using GT911 screens see this tutorial.

void addGT911Screen(int GT911ResetPin,int GT911IntPin);

Adds a GT911 touch screen to the system
Add in void setup() after myLayout.init();

int GT911ResetPin: Pin connected to the GT911 Reset Pin
int GT911IntPin: Pin connected to the GT911 Int Pin


EXAMPLE
myLayout.addGT911Screen(15,2);// Adds a GT911 screen Reset pin = 15, int Pin = 2



void addGT911Button(int xPos, int yPos, int accNum, int press1, int press2);

This function adds a touch screen button point

Touch point coordinates cab be found by using nowGT911Touch(int xPos, int yPos) see below

Touch points like buttons can be configured as constant value... always sends same command

or on/Off press once for on, 2nd time off

int xPos: x position of touch point
int yPos: y position of touch point
int accNum: The accessory address you want the button/input to control
int press1:Value sent 0/1 on first press
int press2: Value sent 0/1 on 2nd press

EXAMPLES

myLayout.addGT911Button(30, 555, 2000, 0, 0); //touch point 30/555 sends instruction to AccDecode 2000 to always go to 0
myLayout.addGT911Button(17, 70, 2000, 1, 1); //touch point17/70 sends instruction to AccDecode 2000 to always go to 1

myLayout.addGT911Button(1002, 43, 2001, 0, 1); //double press 1002/43 sends a command to AccNum 2001 to go 0 first press, 1 second press

//triggered by GT911 touch screen touches void nowGT911Touch(int xPos, int yPos) {
Serial.println("custom function nowGT911Touch");
Serial.print("xPos: ");
Serial.print(xPos);
Serial.print(" yPos: ");
Serial.println(yPos);
}

Custom function found in customFunctions.ino

Displays the current touch point to enable setting up of touch points, can also have custom code added to make your own touch screen functions.


 

PCA9685Servo Driver Boards and Servos

nowRail PCA9685 servos

nowrail has a built in PCA9685 driver specifically for driving servos.

A typical circuit would be as shown below.

WARNING: The ESP32 supplies 3.3v to the PCA9685 VCC pin. The external 5v supply connects to the ESP32 VIN pin and the PCA9685 V+ pin.
DO NOT CONNECT THE EXTERNAL 5V and ESP32 3.3V TOGETHER

All GNDs are common

Each servo should plug into it's own port, shown with common 5v/Gnd to simplify diagram.

Components

PCA 9685 Board
ESP32 Dev Module

nowRail PCA9685 Servo Example

This simplifies the way that servos can be added and controlled. Although PCA9685 boards can be daisy chained each board must have it's own unique address using the solder tabs.

PCA9685 servo boards are configured in the nowrail_user_setup.h

The following lines must be uncommented.

#include "Wire.h"

#define MAXPCA9685SERVOBOARDS 5 //default is 5, increase if required
#define SERVOMIN 450 //servo min value...leave these at the default value unless you understand what this setting is.
#define SERVOMAX 2000 //servo max value...leave these at the default value unless you understand what this setting is.

Once these lines are uncommented use the function below to add servos

To find the angle that the servo needs to move to try using the Servo Setter project.

IMPORTANT From version 1.1.0

void addPCA9685Servo(byte board, byte port, int accNum, int angle0, int angle1, int moveTime);

Pre Version 1,1,0

void addPCA9685Servo(byte board, byte port, int accNum, int angle0, int angle1);

This function adds a servo to a PCA9685 board and is placed in the setup() after myLayout.init();

byte board: //The address of the PCA9685 board the servo is connected to such as 0x40
byte port: The port the servo is plugged into 0-15
int accNum: The acessory num,ber the servo should respond to
int angle0: The angle the servo should move to in degrees 0-179 when direction is 0
int angle1:The angle the servo should move to in degrees 0-179 when direction is 1

int moveTime:The time in milliseconds to complete the movement. 0 = Move instantly, 2000 = takes 2000 milliseconds (2 seconds) to complete move.



EXAMPLE

myLayout.addPCA9685Servo(0x40,15,300, 10, 160);//addPCA9685Servo(byte board,byte port,int accNum, int angle0, int angle1);

myLayout.init();
myLayout.addPCA9685Servo(0x40,15,300, 10, 160, 0);//addPCA9685Servo to board 0x40 on port 15 that responds to accessory address 300. Direction 0 it will move to 10 degrees. Direction 1 will move to 160 degrees and move as fast as possible

myLayout.addPCA9685Servo(0x42,3,210, 45, 162, 2000);//addPCA9685Servo to board 0x42 on port 3 that responds to accessory address 210. Direction 0 it will move to 45 degrees. Direction 1 will move to 162 degrees and complete the move in 2000 milliseconds (2 seconds).


 

PCA9685Servo Driver Boards and LEDS

nowRail pca9685 leds

nowRail has a built in PCA9685 driver specifically for driving LED's.

A typical circuit would be as shown below.

WARNING: The ESP32 supplies 3.3v to the PCA9685 VCC pin. The external 5v supply connects to the ESP32 VIN pin and the PCA9685 V+ pin.
DO NOT CONNECT THE EXTERNAL 5V and ESP32 3.3V TOGETHER

All GNDs are common

IMPORTANT: LED's and Servos CANNOT be connected to the same PCA9685 board as they require different frequencies.

Each LED should plug into it's own port, shown with common 5v/Gnd to simplify diagram.
Each LED connects between the PWM Pin and GND

Components

PCA 9685 Board
ESP32 Dev Module

nowRail PCA9685 LED Servo Example

This simplifies the way that leds can be added and controlled. Although PCA9685 boards can be daisy chained each board must have it's own unique address using the solder tabs.

PCA9685 servo boards are configured in the nowrail_user_setup.h

The following lines must be uncommented.

#include "Wire.h"

#define MAXPCA9685SERVOBOARDS 5 //default is 5, increase if required
#define SERVOMIN 450 //servo min value...leave these at the default value unless you understand what this setting is.
#define SERVOMAX 2000 //servo max value...leave these at the default value unless you understand what this setting is.

Once these lines are uncommented use the function below to add LED's


void addPCA9685Led(byte board, byte port, int accNum, int dirOn, int effect, int maxBright,int effectBright);

This function adds a LED to a PCA9685 board and is placed in the setup() after myLayout.init();

An error message will be seen if you try to connect LED's to the same PCA9685 as a servo.

byte board: //The address of the PCA9685 board the servo is connected to such as 0x40
byte port: The port the servo is plugged into 0-15
int accNum: The acessory num,ber the servo should respond to
int dirOn: The direction that should switch ON the led (1 or 0);
int effect:Type of light 0 = standard on/off, 1 = fire flicker, 2 = gas light, 3 = arc welder
int maxBright:The maximum brightness of the LED
int effectBright:The lowest brightness furing effects (does not have any effect for effect 0

EXAMPLE

myLayout.addPCA9685Servo(0x40,15,300, 10, 160);//addPCA9685Servo(byte board,byte port,int accNum, int angle0, int angle1);

myLayout.init();

myLayout.addPCA9685Led(0x42, 0, 2005, 1, 0, 4095, 0);//addPCA9685Led to board 0x42 on port 0 that responds to accessory address 2005 and Direction 1 will turn the LED on at a value of 4095.

myLayout.addPCA9685Led(0x41, 0, 2006, 1, 1, 4095, 500);//addPCA9685Led to board 0x41 on port 0 that responds to accessory address 2006 and Direction 1 will turn the LED on using a fire effect. Max brightness 4095 minimum brightness of 500.

myLayout.addPCA9685Led(0x41, 1, 2007, 0, 2, 250, 20);//addPCA9685Led to board 0x41 on port 1 that responds to accessory address 2007 and Direction 0 will turn the LED on using a gas light effect. Max brightness 250 minimum brightness of 20.

myLayout.addPCA9685Led(0x41, 4, 2008, 1, 3, 4095, 0);//addPCA9685Led to board 0x41 on port 4 that responds to accessory address 2008 and Direction 1 will turn the LED on using a arc welder effect. Max brightness 4095 minimum brightness of 0.



 

 

Loco and Accessory control functions These functions will send commands to DCC EX if it is configured. In the future I hope to exand this to loconet as well.


These functions are intended for those building their own loco controllers or custom code accessory controllers.

void sendDCCLocoFunc(int dccAddr, byte funcNum, byte funcState);

This function is sends a loco function command to a loco decoder

int dccAddr: The DCC decoder address of the loco
byte funcNum: The DCC decoder function to be set
byte funcState: 0 = turn function off, 1 = turn function on

EXAMPLE

myLayout.sendDCCLocoFunc(1024, 3,1);// This will send a command to loco decoder address 1024 to turn ON function 3

void sendDCCLocoSpeed(int dccAddr, byte dccSpeed, byte dccDir);

This function is sends a locospeed command to a loco decoder

int dccAddr: The DCC decoder address of the loco
byte dccSpeed: The required speed 0-127
byte dccDir: Direction of travel 1 = forwards, 0 = reverse

EXAMPLE

myLayout.sendDCCLocoSpeed(1024, 60,1);// This will send a command to loco decoder address 1024 to set a speed of 60 going forward

myLayout.sendDCCLocoSpeed(1024, 5, 0);// This will send a command to loco decoder address 1024 to set a speed of 5 in reverse


void sendAccessoryCommand(int accNum, byte accInst, byte respReq);

This function is sends a locospeed command to a loco decoder

int accNum: The Accessory Address (only addresses 1-2000 will be passed to DCC EX)
byte accInst: The instruction to be passed( for turnout 0 and 1 ) Higher values could be sent if the accessory is designed to cope with it such as a DFPlayer volume
byte respReq: 0 = no response MESSRESPNOTREQ or 1 = responce required MESSRESPREQ
When a command is sent a response can be required. System will send message 5 times if no response. If something is constantly changing value it is best to turn OFF response.

EXAMPLE

myLayout.sendAccessoryCommand(138, 1, MESSRESPREQ) // Send a command to accessory decoder 138 to move to position 1 and send a response. As the accessory is below 2000 it will be passed to DCC-EX if connected

myLayout.sendAccessoryCommand(3000, 0, MESSRESPNOTREQ); // Send a command to accessory decoder 3000 to move to position 0 I do not need a response. As the accessory is above 2000 it will NOT be passed to DCC-EX if connected


 

Loco Controller functions These functions make it easier to create your own loco controller for systems such as DCC-EX.

Internally nowRail stores the DCC Decoder Address, Function Status and Loco Name (max 20 chars).

If EEPROM enabled (#define NOWDisc in user_setup.h) any changes will be saved to EEPROM and retrieved on system restart

These functions are intended for those building their own loco controllers

int getLocoDCCAddress(byte locoID);

This function gets the loco DCC decoder address from the nowRail internal array of 200 locos.

byte locoID: A value of 0-199 that gets the Decoder number of the loco


EXAMPLE
byte myLocoID = 3;
int DCCAddress;
DCCArddess = myLayout.getLocoDCCAddress(myLocoID);
Serial,println(DCCAddress); //Serial print the DCC decoder address of LocoID 3

void setLocoDCCAddress(byte locoID, int dccAddress);

This function sets the loco DCC decoder address inthe nowRail internal array of 200 locos.

byte locoID: A value of 0-199 that gets the Decoder number of the loco
int dccAddress: A value between 1 - 10238 (some DCC systems will only allow addresses up to 9,999) that the loco should be set to.

EXAMPLE

myLayout.setLocoDCCAddress(3, 1234);//Will update the locoID 3 in the array to DCC address 1234

byte getLocoDCCFuncState(byte locoID, byte funcNum);

This function gets the status of a loco function.

byte locoID: A value of 0-199 that gets the Decoder number of the loco

byte funcNum: A value of 0-63 (current decoders usually have a max value of 28 but this has been future proofed) Returns 0 = Off 1 = On

EXAMPLE

myLayout.getLocoDCCFuncState(2, 4)// This return the value of function 4 for locoID 2

byte getLocoDCCFuncState(byte locoID, byte funcNum);

This function gets the status of a loco function.

byte locoID: A value of 0-199 that gets the Decoder number of the loco

byte funcNum: A value of 0-63 (current decoders usually have a max value of 28 but this has been future proofed) Returns 0 = Off 1 = On

EXAMPLE

myLayout.getLocoDCCFuncState(2, 4)// This return the value of function 4 for locoID 2

String getLocoName(byte locoID);

This function returns a String of the loconame if one has been input (Max 20 chars)

byte locoID: locoID in the nowRail array (0-199)


EXAMPLE

Serial.print("Name ");
Serial.println(myLayout.getLocoName(2));
// Will display the name of locoID 2

void setLocoName(byte locoID, String locoName);

This function sets the Name of the loco (Max 20 chars, extra chars will be ignored)

byte locoID: locoID in the nowRail array (0-199)

String locoName: String of loco name (max 20 chars, extra ignored)


EXAMPLE

myLayout.setLocoName(2, "locoName");// sets the name of locoID 2 to locoName

byte locoGetConsistState(byte locoID);

This function gets the consist staus of the loco

returned values are:

0 .... Not in consist
1 .... Not in consist ... but consist direction set to Reverse
2 .... In Consist (FWD Direction)
3 .... In Consist (Rev direction)... will move in oppostie direction to lead loco.

byte locoID: locoID in the nowRail array (0-199)


EXAMPLE

myConstState = myLayout.locoGetConsistState(locoID);;// will return the consist state of the loco in the loco array (0-199) that is passed to the function in locoID

void locoSetConsistState(byte locoID,byte consistState);

This function sets the Consist state of the Loco

byte locoID: locoID in the nowRail array (0-199)

byte consistState: String of loco name (max 20 chars, extra ignored)

0 .... Remove from consist in fwd direction
1 .... remove from consist in Rev direction
2 .... Add to Consist (FWD Direction)
3 .... Add to Consist (Rev direction)... will move in oppostie direction to lead loco.

EXAMPLE

myLayout.locoSetConsistState(21,3);// sets the locoID 21 into a consist running in reverse to the controlling loco

void locoTXLocoData(byte locoID);

This function transmits the LocoID details passed to it, decoder address, function state and name.

byte locoID: locoID in the nowRail array (0-199)


EXAMPLE

myLayout.locoTXLocoData(10);// transmits LocoID 10 data over network

void setLocoRXState(byte state, byte updateLocoID);

This function sets the receive state for a Loco ID. If receive state is set the locos data will be updated by a locoTXData transmission.

byte locoID: locoID in the nowRail array (0-199)

byte state: 0 ... will NOT receive. 1 ... set to receive


EXAMPLE

myLayout.setLocoName(2, "locoName");// sets the name of locoID 2 to locoName

 

24LC256 EEPROM

ESP32 and ESP8266 boards DO NOT have built in EEPROM.

I have therefore included the ability to add a 24LC256 EEPROM. This currently stores the layout time at regular intervals so that on restarting the layout the clock will continue from it's last position. It also stores an array of loco data storing data for a roster of 200 locos.


The following lines must be uncommented in user_setup.h to use the EEPROM

#include "Wire.h"

#define NOWDisc 0x50 //Default Address of 24LC256 eeprom chip in Board

Once these lines are added the layout clock will update the EEPROM every 2 minutes so that on restart the layout will start from a time within 2 minutes of shut off time.

Loco data is stored in an array that is saved in EEPROM and restored on restart.
This data inclused the loco DCC address.
Loco Function States
Loco Name (maximum of 20 chars).

This data is available in the loco controller functions.

Components

24LC256 EEPROM
ESP32 Dev Module

ESP32 EEPROM Circuit

For more information see 24LC256EEPROM Tutorial


 

DCC EX Connection



The system connects to DCC EX using Serial2 on an ESP32 Dev Module Board.

DCC EX will receive all valid loco speed and function commands as well as any accessory decoder address between 1 and 2000. Addresses higher than these will still be dealt with as normal by nowRail but are invalid on most DCC systems.

The following lines must be uncommented in user_setup.h

#define DCCEXSSERIAL2_ON

If you want to check the commands being sent to DCC EX uncomment this line so commands appear in the serial monitor.
#define DCCEXSERIAL_ON>


IMPORTANT This code in setup() is only required for versions pre Version 1_0_0
in the setup() function of your sketch uncomment the following, they should be before myLayout.init(); is called

Serial2.begin(115200, SERIAL_8N1, 16, 17);//RX2 = pin 16 TX2 = pin 17
Serial.println("Serial2 started...");

Now just connect the TX (pin 17 on ESP32 dev module to the RX pin of your Arduino Uno/Mega that is running DCC- EX.
Now connect the ESP32 to the Arduino GND. Now every commend in nowRail for accessories below 2001 and all loco speed and function commands will be sent to DCC-EX.

Circuit

WARNING: The Arduino Uno/mega is 5v, an ESP32 is 3.3v

The ESP32 can transmit 3.3v to the Arduino without any problem.
However sending 5v from the Arduino to the ESP32 will wreck your ESP32.

As nowRail currently does not receive any transmission from DCC EX it does not require an connection from the Arduino TX pin.

The circuit is just 2 connections.

The first is ESp32 TX2 (pin 17) to Arduino Uno/Mega RX0 (pin 0).


The second connection is to connect the Arduino and ESP32 Gnd's

nowRail to DCC-EX Connection



 

MP3 Player Control

nowRail 1.0.1 MP3 player implementation

MP3 player control was added in Version 1_0_0

The system works over Serial2 so requires an ESP32 Dev Module or an alternate board that has built in Serial2 as all boards will be controlled via Serial2 (UART) control.

MP3 boards that can be used are: DY-SV5W, DY-SV8F, DY-HV8F, DY_HV20T, JQ8900 (Warning: JQ8900 works but is poor quality and I have had 2 failures).

More information on the boards including data sheets are available at:

DY-HV8F and DY_HV20T 10-20W

DY-SV5W, DY-SV8F 5w

JQ8900

Mp3 players: DY-SV5W, DY-SV8F, DY-HV8F, DY_HV20T, JQ8900

The following lines need to be uncommented in nowrail_user_setup.h

//Serial 2 Pins Best on ESP32 Dev Module, some boards DO NOT have Serial 2

#define SERIALRX2 16 //define the Serial2 RX pin for your board
#define SERIALTX2 17 //define the Serial2 TX pin for your board

//MP3 Player DY-SV5W, DY-SV8F, DY-HV8F, DY_HV20T, JQ8900 This sets up Serial 2 using the pins defined in SERIALRX2 and SERIALTX2

#define MP3BUSYPIN 15 //15 is the interrupt pin that is connected to the MP3 Busy pin
#define MP3NUMTRACKS 20 //defaults to 20 commands, increase number if more commands (accessories) are required
#define MP3INTERVALMIN 250 //random time gaps min...WARNING times below 250 may lead to odd results as MP3 player may not react quick enough
#define MP3INTERVALMAX 10000 //random time gaps max
#define MP3VOLUME 27 //default volume (volumes are 0-30)

Circuit Diagram

This is a typical circuit digram(click for larger version) for the various MP3 players.
NOTE: DY-HV8F requires 6-35v, other boards require 5v, check board specs.

nowRail Mp3 player circuit

void mp3PlayVolume(int vol);

This function sets the volume of the MP3 player in a range between 0 and 30 (Max)

This can be called anywhere.

int vol : A value of 0-30 that sets the volume of the board


EXAMPLE

myLayout.mp3PlayVolume(20); //set mp3 volume to 20

void addMP3PlayTrack(int accNum, int dirOn, int trackNum, int maxTrackNum, int mode);

This adds an MP3 command that will respond to a function command and is used in the setup();

int accNum: The accessory number the function responds to

int dirOn : The accessory direction that turns the function on

int trackNum: The track number on the SD Card or internal memory that the function should play if a single track of the first in the range if playing multiple tracks.

int maxTrackNum: The highest track in a range when playing multiple tracks

int mode : 0 = a single track will be played when the function is called. 1 = the tracks in the range trackNum to MaxTrackNum will play in a random order.

EXAMPLES

void setup() {
Serial.begin(115200);//Standard Serial Output to Serial monitor
Serial.println("nowRailV1_0_0");

//Start the system
myLayout.init();//This functions sets up ESP-NOW as well as other items needed for the system to run

myLayout.addMP3PlayTrack(1001,1, 11, 11, 0); //When address 1001 direction 1 is selected track 11 will play once
myLayout.addMP3PlayTrack(1002, 1, 1, 5, 1); //When address 1002, direction 1 is selected tracks 1-5 will play in random sequence
myLayout.addMP3PlayTrack(1003, 1, 6, 10, 1); //When address 1003, direction 1 is selected tracks 6-10 will play in random sequence
myLayout.addMP3PlayTrack(1004, 1, 11, 12, 1); //When address 1004, direction 1 is selected tracks 11-12 will play in random sequence

myLayout.mp3PlayVolume(20); //set mp3 volume to 20
}



 

NCE Cab Bus Connection

nowRail NCE Cab Bus

The system connects to NCE Cab BUS using Serial2 via a MAX485 break out board from a ESP32 Dev Module Board.

nowRail sets itself up as 5 byte smart cab, capable of sending loco speed. function and accessory commands to Cab Bus that will then be processed by the NCE command station.

NCE communication was added in nowRail version 0_8_1

The following lines must be uncommented in nowrail_user_setup.h

#define CAB_BUS_ADDRESS 4 //This line sets up nowRail as a smart cab with address of 4 (be aware NCE PowerCab has a limited number of addresses it polls)

#define RS485ENABLLEPIN 4 //This line sets the pin that the enable pin from the MAX485 module will be controlled thorugh.

If you want NCE clock to be layout Masterclock uncomment this line. Make sure no other node is set as MASTERCLOCK. You DO NOT need an EEPROM as the NCE Cab Bus will control the time.
NOTE: When NCE cab bus starts up Hand controllers time may stop or give strange results for up to 2 minutes while nowRail syncs with the NCE bus time.
There may also be a slight lag if you change the NCE clock speed.
#define MASTERCLOCK_ON

This line should be uncommented (from version 1.2.1 onwards) This decides how loco decoder addresses 1-128 will be passed to the NCE Can bus.

#define CAB_BUS_SHORTADDRON 0

If set to 0 addresses 1-28 will be treated as short addresses(1 - 128), if set to 1 addresses 1-128 will be sent as long addresses 0001 - 0128

IMPORTANT This code in setup() is only required for versions pre Version 1_0_0
in the setup() function of your sketch uncomment the following, they should be before myLayout.init(); is called

Serial2.begin(9600, SERIAL_8N1, 16, 17);//RX2 = pin 16 TX2 = pin 17
Serial.println("Serial2 started...");

Components

MAX485/RS485 Module
ESP32 Dev Module

Now just build up the ciruit below (Click image for larger Version)

nowRail to DCC-EX Connection

Click for larger image

NCE Cab bus circuit

 

 

DCC Controller input

With the addition of a simple bit of circuitry commands from any DCC control system can be passed on to nowrail.

At the moment I have only configured the system for accessory decoder commands.

A step by step walk through of the circuit is available at https://www.digitaltown.co.uk/79DCCDecoderCircuit.php

BLUE wire (the one that connects to pin 2 on the Arduino) to pin 4 on an ESP32 Dev Module


The following lines must be uncommented in user_setup.h

#define DCCDECODERPIN 4 //If board is being used as a DCC decoder this is the interrupt pin
#define ONEBITTIME 130 // If your DCC system does not work you can change this value. NCE systems and DCC-EX seem to work between 130 - 180. Make sure your wiring is correct before messing with this value.

The Circuit

WARNING: Do not conenct your ESP32 directly to the DCC track output.

This is the circuit to connect your DCC track signal to nowRail.

The components you need are:

1 x 6N137 Optoisolator
1 x 1N4148 Diode
1 x 1k Ohm resistor
2 x 10k Ohm resistor
2 x small jumper wires

Components

ESP32 Dev Module

IMPORTANT:

Please note the Orange Jumper running alongside the 2 x 10k Ohm resistors.

Note the Blue jumper running alongside the 1N4148.

 

A step by step walk through of the circuit is available at https://www.digitaltown.co.uk/79DCCDecoderCircuit.php

 

 

 

 

DCC Decoder Circuit




 

JMRI



NOTE: I have had to learn to use JMRI to connect to nowRail. I will describe the set up I have used as it's not a program I use for my layout.

Connection is VIA USB from computer to ESP32.

Two Lines need to be uncommented in user_setup.h

#define JMRICMRI  1  //JMRICMRI connection, this uses Serial at 115200 baud rate, VALUE 1 is CMRI node number (0-127)

#define JMRICMRINUMCARDS 24 //gives 24 x 8 sensors (192), increase value if required

WARNING: Comment out the line
//#define DIAGNOSTICS_ON

This is because any diagnostic data will be sent to JMRI. Note the Serial Monitor WILL NOT work while connected to JMRI

Set up (will be explained in video)

Edit>Preferences

Top Left "Connections"


Add connection:
Manufacturer C/MRI

System Connection:
Serial

Serial Port
Whatever COM port your ESP32 is using

Connection prefix
I left mine as C

Connection name

I left as C/MRI

Check Additional Connection settings

Baud Rate

115200

Output Interval (ms)

Left as 250

Configure Nodes

Node address

I set mine to 1, this will prefix your Lights, Sensors and Turnout numbers

Node Type

I used USIC_SUSIC

Receive Delay

0

Card Size

24-bit

Card Address/Card Type

I set cards 0-7 as OUTPUTS and 8-15 as INPUTS

That gave me 64 INPUTS (sensors) and 64 OUTPUTS (Lights/Turnouts), increase the number of you need more.

Enable Polling at Start up

Checked


 

Diagnostics

Diagnostics posts a lot of information to the Serial Monitor to allow you to see what is happening,

Once you have everything working just comment the line out to turn it off and speed up your system.


The following lines must be uncommented in user_setup.h

#define #define DIAGNOSTICS_ON //Will display all incoming messages in Serial with DIAG> Prefix

 

Button Debounce

This value sets the button debounce level for the layout.

Lower values make the buttons more sensitive but you are more likely to get double presses. Too high a value can make the buttons seem sluggish.

The following line can be edited in user_setup.h

#define BUTTONDEBOUNCE 250 //Set the button debounce speed to 0.25 seconds...increasing value reduces double presses but too high and system is sluggish

 

TURNOUTPULSE

This value sets the pusle length in milliseconds when a pulse is required for solenoid type point motors, lower values will kmake the pulse shorter, higher values will make the pulse longer (for sticky motors).

The following line can be edited in user_setup.h

#defineTURNOUTPULSE 500 //0.5 second pin HIGH to switch point/turnout

nowRail example projects

 

nowRail LCD touch screen controller
nowRail loco controller nowRail v1.2.1 hand controller updates
This is a prototype controller I built for my own Isle of Mudd layout. The controller will work with DCC-EX via the nowRail interface or NCE cab bus, again using the nowRail interface.

The basic controller has 5 components

ESP32 Dev Module
3.5" 480x320 SPI LCD Screen with capacitive touch sensor, I have tested with the ILI9486 FT6236 and ILI9488 FT6236 versions of the screen, see the photos and link below. This is the link to the one I bought . I bought the ILI 9486 FT6236 version from the link.
Rotary Encoder Module
24LC256 EEPROM chip
10k Ohm resistor

The project requires 2 libraries

TFT_eSPI by Bodmer (I used version 2.5.43) I User_Setup config files for the 9486 and 9488 are in the project download file. Can be installed from Arduino Library manager or https://github.com/Bodmer/TFT_eSPI
FT6236 by Dustin Watts https://github.com/DustinWatts/FT6236 version 1.0.2 (included in project download file)

Pin Connections

EEPROM Uses the nowRail configuration see EEPROM

Rotary Encoder: Button (SW) to ESP32 Pin 25, Encoder Left (CLK) ESP32 pin 26, Encoder Right (DT) ESP32 pin 27

LCD Touch screen

ILI9488/6 FT6236 Touch Screen

ESP32 DEV Module

VDD

3.3v

GND

GND

CS

D15

RST

D4

D/C

D2

SDI

D23

SCK

D18

BL

3.3v

SDO

D19

NC/3v3

Not Connected

CTP_SDA

D21

CTP_SCL

D22

CTP_INT

Not Connected

CTP_RST

Not Connected

For basic tutorials on setting up these screens see this link ILI9488

Complete Project Code

Click to download project file : Latest version 20/01/2025 adds consisting and ability to transmit loco data between controllers

Click for Larger version
nowRail loco controller breadboard

This is the type of 480 x 320 screen I am using.

On Aliexpress they are listed as ILI9486 ILI9288 FT6236
This is the link to the one I bought

This is the ILI 9486 FT6236 version from the link above

Click on images for larger versions

TouchScreenRear

TouchScreenRear

Click for Larger version
nowRail loco controller

The STL and DesignSparks for the case are available for download here.
These file are copyright of Digital Town and not for commercial resale or for the building of commercial products without expressed permission.

They may be used by clubs or individuals to build their own controllers without limits.

Further information on case construction is in the Read Me file, the STL files and the original design files can be dlownload for free from cult3D using the link below.

Case 3D Print files

Circuit Diagram, click for larger version

nowRail touch screen controller circuit




nowRail tutorials

nowRail 0.7.2

nowRail NCE Cab Bus

nowRail pca9685 leds

nowRail 1.0.1 MP3 player implementation

Additional Resources

#70 ESP-NOW Broadcast Mode 06/03/2024

Random Nerds Getting Started with ESP-NOW (ESP32 with Arduino IDE)

Random Nerds Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)

Comments


For help or suggestions on new projects, please email the address in this image: and use nowRail as a reference.