Last Updated: 18/02/2026

nowRail

Projects >> nowRail

Latest News

Latest news is also available at the nowRail Facebook Group

26/01/2026 nowRail v1.9.3

New Definitions in nowrail_user_setup.h

#define PCA9685SERVODETACH 600 // Will cause servos to detach from PCA9685 boards affter deinded time period 600 = 0.6 seconds

#define PCA9685LEDOPENDRAIN 1 //Causes all connected LED PCA9685 boards to operate in open drain mode

#define PCA9685FLASHTIMER 1000 // defines the flash period for flashing LED's on PCA9685 boards

Function Update


void addPCA9685Led(byte board, byte port, int accNum, int dirOn, int effect, int maxBright, int effectBright);
effect = 4, LED will flash at the rate set with #define PCA9685FLASHTIMER 1000

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 (Latest Videos)How to nowRail loco decoderHow to nowRail loco decoder
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
Standard Pin functions


Button Video tutorials

Toggle Switch Video tutorials

LED Video tutorial

SensorVideo tutorial

Sensors

nowRail has standard pin functions and CD4021 shift register commands to send sensor data.

Sensor data can be received by JMRI, DCC EX ExRail or processed within nowRail.

Custom data can also be sent using custom sensor functions.
nowRail DCC EX ExRail and sensors

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

Toggle switch 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.
Flashing Crossing style flashing LED's inclduing opposite flash

Open Drain mode for LED's is also available

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
.nowRail System Clock Functions
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
nowRail NCE Cab Bus
DCC EX connection

How to set nowRail to pass DCC loco and Accessory commands to DCC EX. From version 1_8_3 nowRail can pass sensor data to ExRail, digital and analogue values.
nowRail Connecting to DCC-EX nowRail DCC EX ExRail and sensors

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
DCC to nowRail connection
Custom Functions How to get nowRail to trigger your own custom code
Button/Sensor Debounce How to adjust the button debounce sensitivity
TURNOUTPULSE How to adjust the length of a pulse for solenoid type point motors.
Wifi Channel How to set and swap the channels within nowRail
RFID/Barcode data These functions allow the transmission of the bracode or tag UID number or for RFID tags other tag data can be transmitted allowing local processing.
nowRail Barcodes and RFID tags


nowRail - Introduction

nowRail getting started Version 1.4.4 or greater

What is nowRail?

nowRail is a communication protocol for model railways, both analogue and DCC.
It is distributed free of charge under the MIT license.

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), as well as various other newer ESP32 boards. The code has been tested on otherESP32 boards but some lack certain peripherals such as Serial 2 so make sure the board you choose board that has all the features needed for your nowRail set up.
Although in the early days of nowRail ESP8266 was supported as nowRail has grown they with a lack of RAM so will be dropped from futire versions of nowRail.

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)



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


Any suggestions/bugs please email or use the github repository at https://github.com/nowRail/nowRail


Current Stable Version
Version 1.9.3


Version 1.9.3

18/02/2026

New Definitions in nowrail_user_setup.h

#define PCA9685SERVODETACH 600 // Will cause servos to detach from PCA9685 boards affter deinded time period 600 = 0.6 seconds

#define PCA9685LEDOPENDRAIN 1 //Causes all connected LED PCA9685 boards to operate in open drain mode

#define PCA9685FLASHTIMER 1000 // defines the flash period for flashing LED's on PCA9685 boards

Function Update

void addPCA9685Led(byte board, byte port, int accNum, int dirOn, int effect, int maxBright, int effectBright);
effect = 4, LED will flash at the rate set with #define PCA9685FLASHTIMER 1000

nowRail PCA9685 Open Drain, Servo detatch


Current Stable Version
Version 1.8.3


Version 1.8.3

27/01/2026

New Definition

#define REDUCEMASTERCLOCKDIAG This definition in nowrail_user_setup.h reduces the MASTERCLOCK updates to once per minute

New Functions

Ability to send a custom command up to 30 characters long to DCC EX
void sendDCCEXCustomCmd(String cmdString);

Ability to send a custom value to a sensor 0/1 or analogue
void sensorCustomValue(uint16_t senNum, int16_t senValue);

An added function for use within void nowSensorUpdate(int senNum, int32_t senInst) in the customFunctions.ino
This function stops the sensor data being repeated if processed by custom code rather than JMRI or DCC EX/Ex Rail
void sensorProcessed(void);

nowRail DCC EX ExRail and sensors


Version 1.7.1


Version 1.7.1

08/01/2026

New Functions

Toggle/Latching switches standard pins
void addStdPinTSwitch(int pin, int accNum);

Toggle/Latching switches CD4021BE shift register
void addCD4021PinTSwitch(int chip, int pin, int accNum);

Improved error messages when looking for MASTERCLOCK wifi channel


Version 1.6.0


Version 1.6.0

31/12/25

New Functions

RDID tags and barcode data transmission
void sendRFIDData(uint8_t rfidData[],uint8_t len);

New function to receive barcode/RFID data in cuustomFunctions.ino
void nowRFIDDataRec(uint8_t *incomingData, int len)

Current Stable Version
Version 1.5.5


Version 1.5.5

29/11/2025 nowRail v1.5.0

New Functions

void sendClockTimeChange(byte hour, byte mins, byte seconds, byte day);
This function allows the clock time to be set/updated at any time
See Time Functions for details.

Mod/Bug fix

Mods made to GT911 touch screen code due to changes in the ESP32 libraries (3.2.0 or greater)


15/12/25
1.5.5 fixes
The following functions can now be deleted in customFunctions.ino without causing an error when compiling
void nowLocoBulkDataRX()
void nowLocoDataSetRX()

Current Stable Version
Version 1.4.4


Version 1.4.4

Additions

Ability to set Wifi Channel
Ability to Encrypt data packets
Ability to switch wifi channel in real time


New Functions

void set74HC595NPPinState(unsigned int chip, unsigned int pin, byte pinState);
Allows the pin state on a 74HC595np to be changed without a command being sent.
useful for turntables/traversers when multiple pins on control panel need updating.

Mod/Bug fix

Removal of ESP8266 code
. ESP8266 struggles to run nowRail and as better and smaller ESP32's are now available they have been removed from the code base.

Mod to allow loco commands to run without EEPROM updates for those who don't want to use EEPROM
in functions:
setLocoDCCAddress(byte locoID, int dccAddress)
setLocoName(byte locoID, String locoName)
setLocoDCCFuncState(byte locoID, byte funcNum, byte funcState)

nowRAil wifi channels and encryption

Current Stable Version
Version 1.3.3



Version 1.3.3

Bug fix in stdPanelPins


Additions

Adds ability to transmit all loco data between controllers
Ability to change the address of a controller

New Functions

void setnowRailAddr(byte element, int changeVal);
String getnowRailAddr();
void locoTXAllLocoData(void);
void locoRXAllLocoData(int state);

Mod/Bug fix

Under testing I noticed the ppca9685 servo control system when moving a servo at a timed speed would try to start the 1st movement from a position of Zero as the current servo position. This has the potential to move the servo outside the range the user has decided to safely move the servo so the first move now start with the assumption the servo is at the centre 90 degree position. all following moves will move fro the servos known current position.

Issue found with DCC signal reader, now fixed..



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


nowRail, introduction and 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.


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);

Standard Pin functions

Code for video examples

This connects a standard button (momentary switch or stufd and probe) 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.

Other Resources

digitalRead() and Pull Down resistors and debouncing buttons

Controling a relay

void addStdPinTSwitch(int pin, int accNum);

nowRail toggle switches latching switches

Code for video examples

This connects a toggle switch / Latching switch 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.


Examples:

myLayout.addStdPinTSwitch(15, 100); //pin 15 sends to accessory 100 a command of 0 or 1 depending if switch on or off

Other Resources

Digital Pins with Toggle switches

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

Standard Pin functions

Code for video examples

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.

Other Resources

Digital Pins and DigitalWrite() - controlling LED's

Solenoid Turnout control using Mosfets

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

Standard Pin functions

Code for video examples

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.


Other Resources

Digital Pins and DigitalWrite() - controlling LED's

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 nowrail_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 nowrail_user_setup.h

#define MASTERCLOCK_ON //this board is the master clock and will send out a broadcast to sync all other boards
Version 1.8.3 and greater See this video at time point 20:20 for details https://www.youtube.com/watch?v=Eih6xguq3gM
#define REDUCEMASTERCLOCKDIAG This reduces the MASTERCLOCK time outputs to the Serial monitor to once per minute.

 

Time Functions nowRail has a built in layout time clock. Thes speed of the clock can be accelerated, stopped or set to specific times as required.
The clock can also be used to trigger accessories or automation.

nowRail System Clock Functions
Example code from video

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.
void sendClockTimeChange(byte hour, byte mins, byte seconds, byte day);

This function allows the user to set the MASTERCLOCK time either at start up or if they want to jump the clock forwards.
This function is only processed by MASTERCLOCK boards that will then update the layout.


byte hour : The value between 0-23 that you want the clock hour set to.

byte mins : The value between 0-59 that you want the clock minutes set to.

byte seconds : The value between 0-59 that you want the clock seconds set to.

byte day : The value between 0-6 that you want the clockday set to.

Valus that exceed specified range will be set to 0

Example:
myLayout.sendClockTimeChange(10, 30, 15, 2); Sets the MASTERCLOCK board to 10:30:15 on day 2

Added 1.5.0

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,1,1);//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,14,13);
myLayout.addCD4021PinButton(0,1,10,0,1);
myLayout.addCD4021PinButton(1,0,20,0,0);
myLayout.addCD4021PinButton(1,5,20,1,1);


void addCD4021PinTSwitch(int chip, int pin, int accNum);

nowRail Toggle Switches

Allows a toggle / Latching switch to be used instead of a momentary button. Works in the same way as adding a standard toggle switch 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,

Then number of Toggle Pin switch triggers is et in nowrail_user_setup.h
The default value is 8 but this can be changed to the number required.
It is possible to have one pin trigger multiple accessories.

#define NUMCD4021CHIPSNUMTSWITCH 8

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


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.addCD4021PinTSwitch(0,1,10);//chip zero, pin 1 will send an instruction to accessory number 10. The instruction will be 0 or 1 depending if the switch is On or Off

Example 2

Chip 0, Pin 1 will trigger Accessoru Number 10 and 11
myLayout.addCD4021PinTSwitch(0,1,10);
myLayout.addCD4021PinTSwitch(0,1,11);

Setup would look like:

myLayout.init();

myLayout.setupCD4021(12,13,15);
myLayout.addCD4021PinTSwitch(0,1,10)



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 nowrail_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);



void set74HC595NPPinState(unsigned int chip, unsigned int pin, byte pinState);

1.4.4 addition

This function allows the user to manipulate an output pin without using
void add74HC595NPPanelLed(int chip,int pin,int accNum, int dir);
or
void add74HC595NPinAcc(int chip, int pin, int accNum, int dir, int pulse, int setpinState);

I used this in a traverser project when a button press set the new led but didn't unset all the others.
would also be used for turntables.

Called at any time


myLayout.set74HC595NPPinState(2, 6, 0); //Set pin 6 on chip 2 to LOW/OFF

myLayout.set74HC595NPPinState(1, 3, 1); //Set pin 3 on chip 1 to HIGH/ON



 

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 nowrail_user_setup.h

In nowrail_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.
#define PCA9685SERVODETACH 600 //When uncommented any servos will detach after the time period set 600 = 0.6 seconds. This feature can be used to reduce servo chatter and reduces power consumption as servos are effectively powered off when not moving.
#define PCA9685FLASHTIMER 1000 //defines the flash period for flashing PCA9685 LED's
#define PCA9685LEDOPENDRAIN 1 //Sets PCA9685 leds boards to Open Drain Mode

For more information on #define PCA9685SERVODETACH see this video
nowRail PCA9685 Open Drain, Servo detatch

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.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

WARNING: if using #define PCA9685SERVODETACH 600 and a speed of Zero (move as fast as possible) be careful with detach speeds less than 1 second as servo may detach before it completes move. Otherwise the default 600 speed should be OK.

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.
#define PCA9685SERVODETACH 600 //When uncommented any servos will detach after the time period set 600 = 0.6 seconds. This feature can be used to reduce servo chatter and reduces power consumtion as servos are effectively powered off when not moving.
#define PCA9685FLASHTIMER 1000 //defines the flash period for flashing PCA9685 LED's
#define PCA9685LEDOPENDRAIN 1 //Sets PCA9685 leds boards to Open Drain Mode

#define PCA9685LEDOPENDRAIN 1 Means that the LED draws power from the V+ external power supply rather than the Signal Pin supplied with 3.3v from the ESP32. Open drain mode allows more LED's to be connected than the ESP32 3.3v could power.
Open Drain mode also inverts the signal so all effect settings remain the same.

The diagram below shows the difference in connecting LED's with normal and Open Drain mode. (Clicik image for larger version).

PCA9685 Open Drain circuit

Once these lines are uncommented use the function below to add LED's See the video below for more details
nowRail PCA9685 Open Drain, Servo detatch


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

This function adds a Accessory Controlled 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, 4 = Flashing (time period set by #define PCA9685FLASHTIMER 1000).
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.

 

myLayout.addPCA9685Led(0x41, 5, 1234, 1, 4, 4095, 0);//addPCA9685Led to board 0x41 on port 5 that responds to accessory address 1234 and Direction 1 will turn the LED on using a flashing effect. Max brightness 4095 minimum brightness of 0.
The following line creates a flashing LED responding to the same command but flashing opposite to the above LED. This allows oposing flahsing lights for crossings
myLayout.addPCA9685Led(0x41, 6, 1234, 1, 4, 0, 4095);



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

This function adds a Panel Response Controlled 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 = Flashing Led (time period set by #define PCA9685FLASHTIMER 1000).
int maxBright:The maximum brightness of the LED


EXAMPLE

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

myLayout.init();

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

myLayout.addPCA9685PanelLed(0x41, 0, 2006, 1, 1, 4095);//addPCA9685PanelLed to board 0x41 on port 0 that responds to accessory address 2006 and Direction 1 will turn the LED on flashing at a brightness of 4095.

nowRail PCA9685 Open Drain, Servo detatch

 

 

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 nowrail_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

void setnowRailAddr(byte element, int changeVal);

When nowRail starts all boards are given the layout address using the function
nowRail myLayout(0x00, 0x01, 0x02, 0x03);

This function allows the address to be changed while the board is running and was created to allow controllers to be swapped between layout.
The controller will revert to it's original address when restsarted.



byte element: values 0-3 is the section of the address being changed

int changeVal :new address value between 0 and 255


EXAMPLE

myLayout.setnowRailAddr(1,23);// sets the 2nd element of the address to a value of 23

String getnowRailAddr();

This function gets the nowRail address of the unit as a String.
Used mainly in loco controllers




EXAMPLE

myLayout.getnowRailAddr();// Will return a String of the HEX values of the address elements

void locoTXAllLocoData(void);

This function works through the array of 200 locos and transmits their data over the system to any controller set to receive them



EXAMPLE

myLayout.locoTXAllLocoData(void);//data will transmit

void locoRXAllLocoData(int state)

This function allows or stops the controller from receiveing loaco data from locoTXAllLocoData() function.

Controller stops receiving when it has received the full 200 loco transmissions

int state: 0 = Not receiving, >0 will 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 nowrail_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

nowRail Connecting to DCC-EX

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 nowrail_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>

For more information on DCC EX visit https://dcc-ex.com

NOTE: To use BITMAP sensors requires a command station of version 5.5.54 or greater (5.5.54 is the dev version as of 27/01/2026)

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

DCC-EX Controller functions

DCC-EX does not require many specific functions as it passes on Accessory Commands, Loco Speed and Loco function commands from the nowRail system.

NOTE: DCC Accessory commands are limited to values 1-2000. Commands greater than 2000 will work within nowRail but will not be passed on to DCC-EX

sendPowerCommand(byte Command, int dccAddr, byte dccSpeed, byte dccDir)

 

This function sends a Power command to DCC-EX

DCC-EX can be set to power up automatically or a power command can be sent.

The loco data is NOT required for DCC-EX power commands

byte Command: 0 = Turn OFF DCC EX, 1 = Turn ON

int dccAddr: Not required for DCC EX, use 0

byte dccSpeed:Not required for DCC EX, use 0

byte dccDir:Not required for DCC EX, use 0


EXAMPLE

myLayout.sendPowerCommand(1,0,0,0);//Turn on DCC-EX

myLayout.sendPowerCommand(0,0,0,0);//Turn off DCC-EX

void sendDCCEXCustomCmd(String cmdString);

nowRail DCC EX ExRail and sensors

Added in version 1_8_3

This function sends a custom String command to DCC EX and ExRail.
NOTE: This command can be sent from any board but will only be processed by a board with a DCC EX connection.

String cmdString: Will transmit any String up to 30 bytes to DCC EX/ExRail


EXAMPLE

myLayout.sendDCCEXCustomCmd("<Q>"); //List the status of all sensors

myLayout.sendDCCEXCustomCmd("<1>"); //Turn track power on



 

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

Components

MAX485/RS485 Module
ESP32 Dev Module

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

nowRail to DCC-EX Connection

Click for larger image

NCE Cab bus circuit

 

 

DCC Controller input
DCC to nowRail connection
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 nowrail_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 nowrail_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 nowrail_user_setup.h

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

 

Wifi Channel

From 1.4.4 it is now possible to set and even change the wifi channel that nowrail operates on.

nowRail wifi channels and encryption

These functions are designed for extreme exhibition scenarios and are probably not needed even then. However they have been added for peace of mind.

By default ESP-NOW uses Channel 1 or the channel of the access point it is connected to when connecting to an Access Point.

To change the default channel go to nowrail_user_setup.h. Only enter values 1,6 or 11. These are the only non overlapping channels, other channels will degrade the system so nowRail ignores them.
#define WIFICHANNEL 1

Encryption can now be enabled. This should be disbaled if connecting to pre 1.4.4 sketches.
The encryption scamples the layout address in the data packet.
#define ENCRYPT //uncomment to run encryption on broadcasts

The follwing definition when enabled will cause a board to swap between channels 1,6 and 11 at 3 second intervals until it finds the MASTERCLOCK time broadcast so MASTERCLOCK MUst be enabled on one board on the layout.
This allows the layout wifi channel to be changed in real time. This enables the whole layout to swap channel should a channel become distrupted (not that it's ever happened yet).

#define WIFIMASTERCLOCKCHANGE ////this allows the boards wifi channel to be changed while running

The channel chnage function is demonstrated below, this is chnaging the channel to channel 6. The board generating the MASTERCLOCK (even if time is set at Zero) is the board that will instantly change channel (if WIFIMASTERCLOCKCHANGE set) . All other boards will then lose contact with the MASTERCLOCK and will search on other channels after 3 seconds only if WIFIMASTERCLOCKCHANGE is set.
If a loco is added to the layout usnig nowRail as a decoder it will instantly start searching for the MASTERCLOCK even if it missed the command when initially sent.

The fiunction below can be triggered by a button/GT911 or LCD touch screen of choice.

myLayout.changeWifiChannel(6);//send change channel

 

Sensors
nowRail DCC EX ExRail and sensors
nowRail is able to send sensor data to JMRI and from version 1_8_3 to DCC EX ExRail. It can also be processed from within nowRail customFunctions.ino

Data can be sent using the sensor standard pin function or the CD4021BE shift register sensor and also with custom functions.

Binary and analogue data can be sent.

All transmissions are repeated 5 times unless a response is received. JMRI and DCC E$X will automatically deal with the response if running on the layout.

NOTE: To use ExRail BITMAP sensors requires a command station of version 5.5.54 or greater (5.5.54 is the dev version as of 27/01/2026)

void sensorCustomValue(uint16_t senNum,uint16_t senValue);

This function allows users to send a custom sensor value through nowRail.

uint16_t senNum: The sensor number the instruction is meant for, either within nowRail, DCC EX or JMRI
int32_t senValue: The value to send. Be aware that although nowRail can accept high values there may be limits on DCC EX and JMRI

Example:

myLayout.sensorCustomValue(123,1); Sends a value of 1 to Sensor 123

myLayout.sensorCustomValue(321,109); Sends a value of 109 to Sensor 321

void nowSensorUpdate(int senNum, int32_t senInst)

This function is found within the customFunctions.ino tab .
It will be passed any sensor data for cistom processing and is usually dealt with in a switch statement.

void sensorProcessed(void);

This function is used within the nowSensorUpdate function on the customFunctions.ino tab.
It should be called after sensor data has been custom processed to prevent the sensor data transmission being repeated.

 

RFID Tag data and Barcodes

nowRail Barcodes and RFID tags
Click to download code for this video

The use of RFID tags and barcodes has started to become very useful for layout automation.
From 1.6.0 it is now possible to send and receive RFID tag or barcode data.

As people like to use these items in a variety of ways nowRail allows a transmission of up to 30 bytes of data.
This allows for either a tag UID or Barcode number to be transmitted with a location ID or for those who want extra features extra RFID tag data can be transmitted.

Transmit

To transmit data the function used is:

void sendRFIDData(uint8_t rfidData[],uint8_t len);

An example would be:
myLayout.sendRFIDData((uint8_t *) &transmitRFIDDataArray,transmitRFIDDataLength);

This would transmit the data in the array transmitRFIDDataArray that contains transmitRFIDDataLength over nowRail.

Receive

To receive the data there is a new function in customFunctions.ino called

void nowRFIDDataRec(uint8_t *incomingData, int len)

This function allows the data to be processed or passed on to other programs/systems

If multiple variables are being sent with the UID (location ID or other RFID tag data) it can be useful to use a structure using struct. This tutorail gives the basics of using structures and how to move the data in and out of arrays for transmission/reception.


Arduino C++ Serial Communication Part 6 Data Structures, multiple data types

 

Button/Sensor Debounce

This value sets the button/sensor debounce level for the layout.

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

The following lines can be edited in nowrail_user_setup.h
#define SENSORDEBOUNCE 100 //Set the sensor debounce speed to0.1 seconds
#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 nowrail_user_setup.h

#define TURNOUTPULSE 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

nowRail 1.3.0 Loco controller nowRail 1.3.1 Loco controller
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 nowRailV1_7_1_HandController4_0zip 08/01/2026 Ability to change system clocj time in Settings

Previous Versions

nowRailV1_4_4_HandController3_1.zip: 02/11/2025 Bug fixed in Accessory Control. Thanks to Sven Erik for reporting it. channel changes

nowRailV1.3.1HandcontrollerV2.1

PCB files for Download I sent these files to PCBWay and got 5 made for about £8 including postage, VAT and shipping to UK.
The new case files have been designed to use this PCB.

Non PCB Version

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 (original DIY PCB)

Circuit Diagram, click for larger version

nowRail touch screen controller circuit

PCB Version

Click for Larger version
nowRail Hand controller PCB version

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


PCB Files

PCB is used at your own risk.

Download PCB Files

PCB and USB C connector PCB and USB C connector

Click for Larger version
nowRail hand controller PCB version

This version has a battery installed to make it cable free.

noeRail hand controller

The battery I used is located in a small box attached to the case base.

nowRail case battery

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 for PCB Case

29/12/2025 Case design now has alternate base. centre body and screen holder designs to allow for more customisation.

New base versions use captive nuts for the screws.
New screen holder allows for a slightly recessed screen
New centre body allows for a different type of USB connection.

Link to alternate USB connector

alternateCase top

alternateCase base

 

Circuit Diagram, click for larger version

nowRail touch screen controller circuit




nowRail How To Tutorials

nowRail when and when not to upgrade to the latest version of nowRail.

New version of nowRail come out quite often and it's easy to feel pressured into upgrading to the latest version when there is no need to change anything.

As nowRail is backwards compatible this video discusses when and when not to upgrade sketches to the latest version.

It also shows the way that I usually upgrade a sketch when the time has come.

nowRail system monitor

This video shows how to use customFunction.ino to create a system monitor for nowRail.

The monitor allows you to see the commands being send over the nowRail system on an I2C LCD display without the need to connect a computer.

The code also shows how to use some of the different nowRail functions on the customFunctions.ino tab.

Source Code for this video


The I2C LCD Display code is based on the ESP32 1602 lesson, click for more information.

Click image for larger diagramESP32 1602A Liquid Crystal Display Circiut

The custom functions used are:

void nowAccComRec(int accNum, byte accInst)

void nowPanelUpdate(int accNum, byte accInst)

void nowTimeEvents(byte clockSpeed, byte clockHour, byte clockMinute, byte clockSecond, byte clockDay)

void nowLocoFuncUpdate(int locoAddr, byte nowFuncNum, byte nowFuncState)

void nowLocoSpeedUpdate(int locoAddr, byte locoSpeed, byte locoDir)

void nowPowerCommand(byte Command)

nowRail loco decoder dead rail

Source Code for this video

This how to shows the basics of using two functions from the customFunctions.ino tab can easily create a basic loco decoder powered either from the track or battery dead rail systems.

The two functions used are:

void nowLocoSpeedUpdate(int locoAddr, byte locoSpeed, byte locoDir)

This function is triggered when any loco speed or direction change is broadcast.

void nowLocoFuncUpdate(int locoAddr, byte nowFuncNum, byte nowFuncState)

This function is triggered when any loco function change is broadcast.

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.