Welcome to TrainThing’s Raspberry Pi software documentation!¶
Note
Close to done.
Module TT_3¶
Module traffic¶
This module provides:
A socket server for the WiFi connection to the Laptop running JMRI DCC++ software or TrainThing application.
A serial link to the Arduino running the DCC++ Base Station and
Blinks the 4 LEDs representing traffic to and from each.
By default the library module serial creates a serial link to the Arduino with:
EIGHTBITS = 8,
PARITY_NONE = N,
STOPBITS_ONE = 1
- class traffic.Traffic(unicorn)¶
This class handles all TrainThing communication wirelessly to/from the Laptop and wired to/from the Arduino. read_lt() retains commands from the Laptop NOT intended for the Arduino Base Station. Calls to send_to_lt() and write_lt() are used to return status from the Raspberry Pi to the Laptop.
Constants:
- BAUDRATE = 115200¶
(int) - Serial baud rate to the Arduino.
- DEVICE_NAME = '/dev/ttyACM0'¶
(str) - Serial name for the Arduino.
- FORMAT = 'utf-8'¶
(str) - Format for string/byte messages.
- PORT = 2560¶
(int) - Serial port used between RPi and Laptop.
- SERVER_IP = '192.168.1.149'¶
(str) - IP address of the RPi internet server used by Laptop.
- VERBOSE = True¶
(boolean) - more print statements for troubleshooting of the class traffic.
- NO_BS = False¶
(boolean) - Run Raspberry Pi without Arduino base station
- __init__(unicorn) None ¶
Defines and starts the WiFi socket to the Laptop.
Defines a serial link through a USB port to the Arduino Base Station.
Starts threads to read from the LapTop and Arduino.
Init class monitor.
- Parameters
unicorn – Link to the instance of module unicorn created in module TT_3 and passed to module Command.
- read_lt() None ¶
This method is a thread started by __init__ to reads strings from the laptop each ending with “>” command.check is used to see if an instruction from the laptop is for the Arduino, RPi or both. Passes input to write_BS for the Arduino, Pass input to command.process for the RPi or both. Passes Monitor.from_LT the length of the message to blink the orange LED Method loops till shutdown
- send_to_lt(responses: list) None ¶
Send strings to write_lt one at a time from the list of responses Some commands return a list of more than one response.
- Parameters
responses (list) – List of strings each bounded by “<” and “>”
- write_lt(message: str) None ¶
Writes to the Laptop the string passed as a parameter. Passes Monitor.to_LT the length of the message to blink the blue LED
- Pram str message
Status returned for a laptop command or sensor update.
- write_bs(message: str) None ¶
Writes to the Arduino the string passed as a parameter from read_lt. Passes Monitor.to_BS the length of the message to blink the orange LED
- Pram str message
Command from LT to Arduino base station
- read_bs() None ¶
This method is a thread started by __init__ to reads strings from the Arduino each ending with “>”. Strings from the Arduino are passed to write_lt Passes Monitor.from_BS the length of the message to blink the blue LED
- static stop_servers(self) None ¶
end all wifi and serial connections
- class traffic.Monitor¶
This class is used to blink each of the 4 traffic monitoring LEDs in relationship to the traffic Out from the laptop (Orange) and Back to the laptop (Blue). Output to the Base Station (Orange) and Back from the Base Station (Blue).
Should be called only be Traffic
Constants:
- VERBOSE = True¶
(boolean) - If True extra print statements are output.
- DIV = 30¶
(int) - Divisor for the message size to determine the number of blink for the LED
- __init__() None ¶
Set up the IOPi HAT pins for traffic monitoring LEDs IOPi HAT Bus 2 using pins 9 - 12
- _blink_it(led: int, num: int) None ¶
Common routine to blink a LED number of blinks = 1 + num // DIV (integer divide).
- Parameters
led (int) – output pin on IOPi bus2 of the LED to blink
num (int) – number of bytes in the message i.e. len(message)
- from_lt(num: int) None ¶
Creates a thread to Blink the ORANGE LED for traffic from the Laptop.
- Parameters
num (int) – length of the message received i.e. len(message)
- to_lt(num: int) None ¶
Creates a thread to Blink the BLUE LED for traffic to the Laptop.
- Parameters
num (int) – length of message sent to the laptop
- to_bs(num: int) None ¶
Creates a thread to Blink the ORANGE LED for traffic to the Base Station.
- Parameters
num (int) – length of message sent to the Base Station
- from_bs(num: int) None ¶
Creates a thread to Blink the BLUE LED for traffic from the Base Station.
- Parameters
num (int) – length of message received from the Base Station
Module command¶
This module manages configuration of data retained by the RPi and instructions passed from the Laptop.
All access to the configuration information is controlled by Classes Sensor and Signal.
Classes Sensor and Signal implement all DCC++ instructions (and addon commands) processed by the RPi using assets controlled by Classes wabbitFB and signals.
The aspect of each signal is mirrored on the unicorn LED matrix
- class command.Command(unicorn)¶
This class processes all commands from the TrainThing laptop (4) intended for the Raspberry Pi (3)
Traffic.from_LP uses function command.check to identify which instruction go where.
If intended for the RPi command.process is passed the command
Constant:
- VERBOSE = True¶
(boolean) - If True print statements are output for development and troubleshooting
- __init__(unicorn)¶
Defines list of single letter commands sent by the laptop to be executed by the RPi.
Create an instance of Classes Sensor and Signal which execute appropriate commands and retain configuration data.
- cmd_sensor¶
(dictionary) - Of sensor related commands and if intended for RPi only (2) or both (1)
- cmd_signal¶
(dictionary) - Of signal related commands and if intended for RPi only (2) or both (1)
- cmd_other¶
(dictionary) - Of other commands
- check(msg: str) int ¶
Uses the one letter command to determine whether an instruction is intended for the RPi or Arduino or both.
DCC++ command “S” is an exception.
<S ID PIN PULLUP> or <S ID>
IF ID <= 50 then command is passed to the Arduino only
IF ID > 50 then command is processed by RPi only
<S> Command processed by BOTH RPi and Arduino
- Parameters
msg (str) – command message from the LapTop
- Returns
(int) 0 - Arduino only (default), 1 - both, 2 RPI only
- Raises
ValueError – If received command format is invalid or ID < 51
TypeError – If param are not digits
- process(msg: str) list ¶
Processes all commands to be handled by the RPi Function Signal.process , Sensor.process or other_process are called to manage each group of commands.
- Parameters
msg (str) – command from the Laptop
- Raises
ValueError – If command code is invalid
- other_process(msg: str) list ¶
Processes other commands for the RPi
Maybe only <s> current Raspberry Pi status
- Parameters
msg (str) – Command from the laptop
- Returns
Current status of the RPi. Several lines.
- Raises
ValueError for invalid command letter
- class command.Signal(unicorn)¶
this class processes all commands for signals added to the DCC++ structure.
- data_file = 'signals.pkl'¶
- __init__(unicorn)¶
Read from memory the file that containing all information defining signals. Initialize all signals and display on the unicorn
- process(msg: str) list ¶
Process all commands to define/maintain/set the aspect of all signals.
Function signals.Signals.set or signals.LED.set are called to change the physical signal.
Function unicorn.TT_Display.set_signal is called to update the appropriate pixel on the unicorn display.
- Parameters
msg (str) – command sent from the Laptop
- Returns
list of return string for the command
- Raises
ValueError – If command is invalid
Todo
fan figure out why _yellow does not show as a constant.
Module fan¶
This module displays the status of the RPi cooling fan on the TrainThing unicorn LED matrix. Low lever hardware functions are called from the FanLib module and status is displayed by calls to module unicorn.
- class fan.Run(unicorn)¶
This class runs as a thread in the background as long as TrainThing is running. Using FanLib functions to control the cooling fan, monitor the RPi cpu temperature & frequency, fan status and mode. Information is displayed on the TrainThing unicorns LED matrix.
Fan off - GREEN, Fan on RED
CPU Freq = MAX - GREEN (1500MHz), Freq = MIN (600MHz) - RED, else YELLOW (1000 or 750 MHz)
Fan auto mode - GREEN, Manual mode - YELLOW
Hardware has a hard Temperature threshold of 85 C and a soft threshold of 80 C. Using ON_threshold and OFF_threshold the fan on-off hysteresis is controlled. The 5 step temperature ladder displayed on the unicorn matrix is:
Temp >= ON_threshold
ON_threshold > Temp >= OFF_threshold + 3*(on-off Δ)/4
OFF_threshold + (on-off Δ)4 > Temp >= OFF_threshold + 2*(on-off Δ)/4
OFF_threshold + 2*(on-off Δ)/4 > Temp >= OFF_threshold + (on-off Δ)/4
OFF_threshold >= Temp
- Raises
ValueError – If constant ON_threshold <= OFF_threshold.
Constants:
- UPDATE_TIME = 2.0¶
(float) Time between display updates
- ON_threshold = 65¶
(int) The degrees C when the fan is turned on in the auto mode. RPi hard threshold of 85 C, soft 80 C
- OFF_threshold = 55¶
(int) The degrees C when the fan is turned off in the auto mode. OFF_threshold must be less than ON_threshold
- __init__(unicorn) None ¶
Initialization starts the FanLib passing the named parameters on_threshold, off_threshold and auto_time so both modules, fan and FanLib, have the same values so the unicorn display set by this module and the auto mode run by FanLib are synchronized. Makes unicorn display methods available and starts the _main() method as a thread.
- Parameters
unicorn (link) – Link to instance of module unicorn created in TT_3. Used to display the current status of the fan.
- Variables
run_forever (bool) – Set to True by _main() in the beginning. Set to False by function stop() to stop updating the fan status.
- _main() None ¶
This method sets up the initial display values and then every 2 seconds checks status and updating the display for:
The fan is on or off.
The fan is running in the manually or auto mode.
The cpu frequency is Max, Min or in between.
the cpu temperature 5 step display ladder.
until variable run_forever is set False by function stop()
Constant:
- stop() None ¶
This function is called to end updating of the fan status on the unicorn by setting run_forever False. FanLab is called to set_fan to False stopping the fan. And the fan status area of the unicorn is cleared.
Todo
FanLib Add option for PWM or GPIO fan control
Module FanLib¶
This library provides low level functions to manage the cooling fan for the Raspberry Pi. The Pimoroni FanShim FanLib library was used as a model to build my implementation to control a cooling fan powered by an output from a PWM on a 16-channel PWM/servo HAT and a separate control button connected to a GPIO pin.
the FanShim uses GPIO pins that are also mapped to the I2C interface which is heavily used by TrainThing.
__version__ = ‘0.0.3’
v 0.0.1 button
v 0.0.2 add fan and parameters
v 0.0.3 add temp and freq
v 0.0.4 PWM or GPIO fan control
- class FanLib.Fan(pin_button: int = 19, button_bounce_delay: float = 0.05, button_hold_time: float = 4.0, no_button: bool = False, fan_i2c_addr: int = 64, fan_channel: int = 0, preempt: bool = True, auto_time: float = 2.0, on_threshold: int = 65, off_threshold: int = 55, verbose: bool = False)¶
This class handles the low level hardware interface to:
Run the fan
Monitor the cpu temperature
Monitor the cpu frequency if enabled
Monitor the fan control button if enabled
If in the auto mode (default), method _start_auto() is called to start method _run_auto() as a thread to updates the state of the fan based on cpu frequency, temperature and input parameters.
- __init__(pin_button: int = 19, button_bounce_delay: float = 0.05, button_hold_time: float = 4.0, no_button: bool = False, fan_i2c_addr: int = 64, fan_channel: int = 0, preempt: bool = True, auto_time: float = 2.0, on_threshold: int = 65, off_threshold: int = 55, verbose: bool = False) None ¶
Initializes the hardware and starts the function _run_auto() as a thread running the fan in the auto mode.
If the fan button is enabled (no_button: False), an interrupt is established to monitor the button, on GPIO pin pin_button. The function _interrupt may change variables _fan_auto (auto/manual mode) and _fanON (fan on/off).
- Parameters
pin_button (int) – BCM pin # for fan control button. Default 19
button_bounce_delay (float) – Time in seconds delay to debounce the fan button. Default 0.05 second
button_hold_time (float) – Time in seconds to hold button to change fan mode. Default 4.0 seconds
no_button (boolean) – Disable button input. If True fan in auto mode. Default False
fan_i2c_addr (int) – I2C address of PWM controlling the fan. Default 0x40
fan_channel (int) – Sub address of PWM controlling the fan. Default 0
preempt (boolean) – Monitor CPU frequency and activate cooling preemptively. Default True
auto_time (float) – Time in seconds, between updates in auto mode. Default 2.0 seconds
on_threshold (int) – Temperature threshold in degrees C to auto start fan. Default 65
off_threshold (int) – Temperature threshold in degrees C to auto stop fan. Default 55
verbose (boolean) – Print Output temp and fan status messages. Default False
- Raises
ValueError – IF argument on_threshold <= off_threshold
- Variables
_fanON (bool) – True when the fan is running.
_fan_auto (bool) – True when the fan is in the auto mode.
- get_fan() bool ¶
returns the current value of _fanON, whether or not the fan is running.
- Returns
(Boolean) True if the fan is running
- toggle_fan() bool ¶
Toggle fan state. Calls set_fan to turn the fan on or off and change the value of _fanON
- Returns
(Boolean) The new state of the fan
- set_fan(fan_state: bool) bool ¶
Set the fan on/off. Based on fan_state change the state of the fan and _fanON
- Parameters
fan_state (boolean) – Desired state of the fan
- Returns
(Boolean) The new state of the fan (_fanON)
- static get_cpu_freq()¶
Calls hardware utility to get the current CPU frequencies. Named tuples, current, min and max.
- Returns
(dict) Frequencies in MHz
- static get_cpu_temp() float ¶
Calls hardware utility to get the current CPU temperature.
- Returns
(float) degrees C
- get_fan_auto() bool ¶
Returns the current mode of the fan, _fan_auto
:returns (Boolean) True if fan in auto mode
- _start_auto() None ¶
Starts procedure _run_auto as a thread to run the fan in the auto mode.
- _run_auto() None ¶
Runs the fan in the auto mode as a thread while the fan is in the auto mode (_fan_auto True)
Checks the cpu temperature (get_cpu_temp()) to turn the fan on or off (toggle_fan()) based on on_threshold and off_threshold.
If enabled (_preempt True) checks the cpu frequency (get_cpu_freq()) and keeps the fan running if the frequency is not the max freq.
- _interrupt() None ¶
If the fan control switch is enabled (default no_button = False) an interrupt is established in __init__ to monitor the fan control switch connected to pin_button. When the button is pressed (falling edge of pin_button) this function is called.
The fan control button has 2 functions based on the status of variables _fan_auto, _fanON & button_hold_time and the length of time the button is held down.
If in the auto mode (_fan_auto True) and the button is held for more than the param button_hold_time
The fan will be switch to the manual mode of operation, (_fan_auto False) and the fan is stopped (_fanON False).
If in the manual mode (_fan_auto False)
If the button is held for less than the button_hold_time , the fan will be toggled on or off (_famON changed).
If the button is held for more than the button_hold_time , the fan will be switched to the auto mode, (_fan_auto True) and the fan is stopped, (_fanON False).
Module sensor¶
This description is to short. TODO: Need to put some words here in sensor
- class sensor.Sensor¶
All methods to access stored sensor data
- data_file = 'sensor.pkl'¶
- __init__() None ¶
read sensor table from memory
- pickle = <module 'pickle' from '/usr/lib/python3.7/pickle.py'>¶
- process(msg: str) list ¶
Processes commands to define/maintain/report status of all turnout sensors
- Parameters
msg (str) – Command from the LapTop
- Returns
One or many status lines
- Raises
ValueError – if command char/values in param msg are invalid
TypeError – if param includes not digits char
- sensor_change(pin: str, value: int, hi: bool) None ¶
Called by WabbitFB in response to a sensor change
- Parameters
pin (str) – 1,2,3 byte of sensor hardware pins
value (int) – byte of sensor bits that changed
hi (bool) – sensors in value changed to high (true) or low (false)
Module signals¶
This module directly controls all the signals on the TrainThing layout. A command to change the aspect of a signal is sent from the LapTop (4) received by module traffic, passed to module command/Signal, combined with stored information and sent to this module which changes the aspect of a semaphore or LED signal.
A thread is created for each semaphore change so that the change is not “instantaneous” nor blocking of other operations.
- class signals.Signals¶
This class defines the interface to the semaphore signal hardware and sets the aspect of each semaphore.
Constant:
- VERBOSE = False¶
(bool) used for troubleshooting when True
- __init__() None ¶
Defines the semaphore hardware interface
- set(row: int, col: int, old: int, new: int) None ¶
Starts a thread to change a semaphore aspect. Calls _move()
- Parameters
row (int) – which PWM HAT/Bonnet 0 - 3 {0x40 - 0x43}
col (int) – which output of the row 0 - 15
old (int) – current servo setting 0 - 180
new (int) – new servo setting 0 - 180
- Raises
ValueError – If a parameter is out of range
- class signals.LED¶
This class defines the hardware interface to the four tri-color LED signals in the parking lot and sets the aspect of the LED signals.
Constant:
- VERBOSE = False¶
(boolean) more print statements for troubleshooting of the class LED.
- PINS = {33: [12, 13, 16], 34: [25, 5, 6], 35: [22, 23, 24], 36: [17, 18, 27]}¶
Assign GPIO pins for signals red, yellow, green
- __init__() None ¶
Defines GPIO pin interface to the LED signals
- set(signal: int, aspect: int) None ¶
Set the LED signal aspect
- Parameters
signal (int) – Signal to set 33 - 36
aspect (int) – 0-3, off, red, yellow, green
- Raises
ValueError – If a parameter is out of range
Todo
traffic Output interrupt driven sensor changes to the laptop
Module unicorn¶
This module provides: an interface to the two Unicorn HAT HD 16x16 displays used to show the aspect of TrainThing signals in place of/ or in addition to, the actual semaphores and display the state of the Raspberry Pi cooling fan.
Functions are provided to simplify, for TrainThing, the interface with the UnicornHATHD2 library.
- class unicorn.TT_Display(color: str = 'BLUE')¶
Procedure to display: Aspect of all TrainThing signals Status of the Raspberry Pi fan
Constants:
- OFF = 0¶
(int) LED Signal off
- RED = 1¶
(int) Signal aspect red
- YELLOW = 2¶
(int) Signal aspect yellow
- GREEN = 3¶
(int) Signal aspect green
- __init__(color: str = 'BLUE') None ¶
Initialize settings for the two Unicorn HAT HD matrix. By default, sets each pixel representing a TrainThing signal to BLUE. If color is set to anything else each pixel/signal is set to the expected initial aspect.
The eight pixel locations used to display the fan status are always initially BLUE
- Parameters
color (str) – If NOT “BLUE” then expected initial signal aspects
- set_signal(x: int, y: int, aspect: int) None ¶
Update the displayed aspect of a signal at location {x,y}
- Parameters
x (int) – coordinate of the pixel 2-31
y (int) – coordinate of the pixel 0-15
aspect (int) – 0-3 ~ OFF|RED|YELLOW|GREEN
- Raises
ValueError – If a parameter is out of range
- set_fan(x: int, y: int, r: int, g: int, b: int) None ¶
Set a fan status pixel at location {x, y} with the given RGB levels.
- Parameters
x (int) – coordinate of the pixel 0-1
y (int) – coordinate of the pixel 0-4
r (int) – intensity of red 0 - 255
g (int) – intensity of green 0 - 255
b (int) – intensity of blue 0 - 255
- Raises
ValueError – If a parameter is out of range
- static off() None ¶
Clears the unicorn buffer and display
Module wabbitFB¶
This module provides the interface between Wabbit optic-isolators, the IOPi HAT, and the RPi.
The wabbits provide the status of each TrainThing turnouts to IOPi HAT.
The IOPi sends an interrupt to the RPi
The RPi then reads the IOPi inputs and reports changes in status of the turnouts to the Laptop.
Class WabbitFB Method Interrupt is called when any of the 24 optic-isolators/IOPi bits change.
- class wabbitFB.WabbitFB¶
This class defines and handles the interrupts generated by the IOPi HAT in response to turnout status changes reported by the 6 Wabbit decoder boards part of TrainThing.
Defines a method to report the status of all defined IOPi pins.
Each of 6 Wabbit controls 2 turnouts reporting the CLEAR and THROWN status to (4) input pins on the IOPi HAT. In response the IOPi generates one of three hardware interrupt connected to Raspberry Pi GPIO pins 4, 0 or 1. The RPi generates interrupts in response to the GPIO pin changes calling method _interrupt within this class. The method reports the change in sensor status to the laptop.
Constant:
- __init__() None ¶
This method:
Initializes the IOPi bus1, port 0 & 1 and bus2 port 0 as inputs from the Wabbits. (NOT bus2 port 1.)
Initializes output interrupts for the 3 ports connected to GPIO pins
Initializes 3 GPIO pins as input interrupts to the RPi 4 0 1
- static _bits(n: int) str ¶
Change byte n to a binary string (Testing only)
- Parameters
n (int) – A numeric byte
- Returns
(str) A 9 character string representing the 8 bits in the byte. 8765 4321
- static _fix0(old: int) int ¶
Fix wiring error on Wabbit Feedback board, IOPi bus 1, port 1, bits 10 and 12 switched
- Parameters
old – byte read from bus 1 port 1 xxxx AxBx
- Returns
byte with bits switched xxxx BxAx
- _interrupt(interrupt_pin: int, new: int, old: int) None ¶
Function called when GPIO 0,1,4 goes low. Identifies sensors that changed
- Parameters
interrupt_pin (int) – which GPIO pin caused the interrupt
Passes to output the interrupt_pin, which bits changed and the current value of the byte causing the interrupt.
- Raises
ValueError – if parameter is invald
- one_state(pin: str) list ¶
Returns the state of one sensor called by command.Sensor - <Q> :pram str pin: 2 char byte and bit of sensor :returns: the pin requested and the current bool state 0/1 :raises ValueError: if pram value is not valid :raises TypeError: of pram is not 2 digits
- _delayed(pin: int, went_hi: int) None ¶
Thread to delay setting show bits going high
- Parameters
pin (int) – interrupt-pin
went_hi (int) – byte of sensor that went high