I've been exploring this recently, and I wanted to share my experiences in the hopes that they are useful to others. There are a few ways this can be accomplished. Some are possible out of the box, and others require extra hardware or 3rd-party software.
Typical Package Contents
Here's the electronics we typically get out of the box with a Powered Up train set:
- Powered Up City hub (28738). This includes two I/O ports (used for a motor and possibly lights). The City hub does not include an accelerometer, compass, or GPS, so there is limited feedback provided. It does include a programmable RGB LED and a button.

- Train Motor (28740). This motor is one of only two Powered Up motors that do not include rotation and distance tracking, so there is no easy way to know how far the train has traveled, but we are able to adjust its relative speed.

- Lights (22168) may be included as headlights for the train.

Programming using Powered Up App
The default experience in the Powered Up app provides a controller for the train, but we can also automate the train using a Scratch-like programming environment. This environment is powerful, but the hardware at our disposal is quite limited as a robotics platform. In particular, the included hardware has no useful sensors, which makes the environment unobservable.
If we start the train from a known location, we can run it at a set approximate speed for a certain amount of time, leaving it at a new approximate location. Unfortunately, these locations will change slightly over time, as we have no way of sensing exactly far we have traveled. This might be fine if you just want the train to move for a while then stop for a while, but if you want to stop at stations, things get trickier.
One solution is to induce the train to stop at a known location regularly, such as a siding. We can intentionally stall against the buffer on the siding to reset to a known position.
Adding Sensors
If we're willing to add some additional hardware, things can get much more advanced. One option is to add a color sensor to the bottom on the train:

We can connect the sensor to the port not being used by the motor.


With this in place, we can modify our track by adding plates or tiles of different colors to indicate location on the track or particular actions to take. In this way, we can have the train reliably stop at stations or take other actions. Here's an example program that allows the train to wait when it sees red under the color sensor:

This is similar in concept to the DUPLO trains in terms of input, but we can program the colors to change behaviors in any way we'd like.
We could also choose to add a different sensor, such as a distance sensor or a tilt sensor. Alternatively, we could replace the City hub with a larger hub and add multiple sensors, but this would likely require redesigning the train and would add significant cost.
Standalone Operation
One of the weaknesses of the City Hub currently is that it requires a tethered Bluetooth device, such as a phone, tablet or computer, in order to function. By flashing the custom Pybricks firmware to the hub, we can overcome this limitation and write programs directly to the device. This is especially useful for public displays or other use cases where Bluetooth connections may become problematic.
Here is an example Pybricks program that would allow a train to run for 10 seconds and then pause for 35 using the RGB LED on the hub to indicate its status:
"""
Simple automated train that runs for 10 seconds then pauses for 35
Light transitions from red to orange to yellow as timer counts down
"""
from pybricks.hubs import CityHub
from pybricks.pupdevices import DCMotor, Light
from pybricks.parameters import Button, Color, Direction, Port, Stop
from pybricks.robotics import DriveBase
from pybricks.tools import wait, StopWatch
hub = CityHub()
motor = DCMotor(Port.A)
while True:
hub.light.on(Color.GREEN)
motor.dc(60)
wait(10000)
motor.dc(0)
hub.light.on(Color.RED)
wait(15000)
hub.light.on(Color.ORANGE)
wait(15000)
hub.light.on(Color.YELLOW)
wait(5000)
I use a setup similar to the above to allow an automated train to run around my son's city without the need to have a screen nearby the whole time.