Skip to content

bwooshem/water_heaters_testings

 
 

Repository files navigation

CTA-2045 UCM with Raspberry Pi Libraries

Software package to use a Raspberry Pi as a CTA-2045 UCM for a grid-connected water heater.

Key features

  • Installation script to quickly install all dependencies and compile the code
  • Basic scheduling tool

Please note this is a pre-alpha proof of concept demonstration, and it has only been tested once. There may be bugs or glitches.

Requirements

  1. Raspberry Pi: We tested with 3B+ and other models should work
    1. MicroSD card, at least 32 GB (~$10)
    2. Computer monitor & display cables to the Pi (it may also be possible to SSH to the Pi)
    3. Mouse & keyboard
    4. Power supply (~$10)
  2. USB to RS-485 adapter (~$15)
  3. AWG 22 wire. Note: for short lengths (<10cm) between the adapter and the port on the water heater, it should work fine with regular wire. Longer lengths are recommended to use shielded wire to prevent signal interference. If purchasing shielded wire, only 2 strands are necessary.
  4. CTA-2045 compatible water heater (may work with other SGD)

Installation

  1. Use Raspberry PI Imager from another computer to install Raspbian/Raspberry Pi OS with Desktop, 32-bit (Tested with the version from 13 May 2025, Kernel 6.12, Debian 12). Other versions probably will work too.

    • When setting it up, the username must be “pi”. If you use another username, something in the C++ code will fail later on. You can fix that by creating a new user called “pi”, but then adjusting all the sudoer and auto login permissions is a pain so best to just start with a user called “pi”. The name of the Raspberry Pi device can be anything.
  2. Connect the Raspberry Pi to a power supply, display, mouse, and keyboard. Insert the SD card.

  3. Download or clone this repo. For best results, make sure it is under /home/pi/water_heaters_testings

  4. Run the installation script and follow the prompts there.

cd water_heaters_testings
sudo bash CTA2045_UCM_Installer.sh
  1. Restart the Raspberry Pi
  2. Assemble the system as shown in the figure below.
    • Pin 1: B- (blue wire in the photo)
    • Pin 7: A+ (green wire in the photo)

Photo of wiring for Raspberry Pi, RS-485, and CTA-2045

Usage

Mode Options

Mode Letter Code Notes
CriticalPeakEvent c 5 --
EndShed e 6 Returns system to default mode
Shed s 7 --
GridEmergency g 8 Shuts all heating elements
Loadup l 9 --
OutsideCommunication o 10 Send this first to initialize receiving signals (performed automatically in the launcher script)

Setting a schedule

Create (or edit) the file called demo_schedule.csv. The file should have 2 columns, "Time Elapsed" in seconds, and "Mode". The launcher will run the mode listed after the specified time since the start of the run has elapsed. For example, in the table below, it will run "l" for load up at 30s, "s" for shed at 120s, and "c" for critical peak at 360s. Note that it will keep sending the last mode in the file indefinitely. For a mode left running for more than 5 minutes, the code re-sends the mode every 5 minutes to ensure the water heater keeps the mode setting.

Time Elapsed [s] Mode
30 l
120 s
360 c
... ...

Running the launcher script

cd water_heaters_testings
sudo python3 launcher.py

The launcher script will follow the schedule specified in demo_schedule.csv

Example Operation

The Launcher script has series of command line/terminal outputs to indicate current status. Sections with the tag [Launcher] are outputs created by the launcher script. Those with the tag [UCM Output] are from the UCM C++ code. There may be a lot of other outputs not shown here that are not relevant.

When first started, the launcher will show the following output (with different timestamps).

[Launcher] Beginning UCM Launcher Code. To exit program, use Ctrl + c 
[Launcher] Starting 'sudo dcs/build/debug/sample2' as a subprocess...
[Launcher] UCM process started...
[UCM Output] 2025-08-28 12:04:35,867 INFO  [default] starting commodity service...
[UCM Output] 2025-08-28 12:04:36,012 INFO  [default] ack received: 16
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default] message type supported received: 2
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default] commodity response received.  count: 3

It will show a block of telemetry outputs at the start and again every 1 minute. These are generally not needed.

[UCM Output] 2025-08-28 12:04:36,140 INFO  [default] commodity data: 0
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default]         code: 0
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default]   cumulative: 0
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default]    inst rate: 0
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default] commodity data: 1
[UCM Output] 2025-08-28 12:04:36,140 INFO  [default]         code: 6
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default]   cumulative: 726
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default]    inst rate: 0
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default] commodity data: 2
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default]         code: 7
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default]   cumulative: 375
[UCM Output] 2025-08-28 12:04:36,141 INFO  [default]    inst rate: 0
[UCM Output] 2025-08-28 12:04:36,331 INFO  [default] ack received: 13
[UCM Output] 2025-08-28 12:04:36,443 INFO  [default] operational state received 4

When it is ready to accept a command, it displays this menu (sometimes a glitch will cause it to show the menu multiple times)

[UCM Output] c- CriticalPeakEvent
[UCM Output] e- Endshed
[UCM Output] g- GridEmergency
[UCM Output] l- Loadup
[UCM Output] o- OutsideCommunication
[UCM Output] s- Shed
[UCM Output] q- Quit
[UCM Output] enter choice: 

At the start, the launcher must send the 'o' signal to initialize

[Launcher] Sending o- OutsideCommunication to initialize...

When initialization is complete, it will display the following output. The schedule is a list of times (in seconds from the start) followed by the list of corresponding commands.

[Launcher] Successfully initialized :)
[Launcher] Beginning sending signals using following schedule: 
[30.0, 65.0, 90.0, 150.0, 220.0]
['s', 'l', 'g', 'e', 'c']

When it sends a given signal, the launcher will show the following message. The UCM responds with app ack received if it was able to successfully run the command. (note that on rare occasions, it will say app nak received, indicating it did not run the command - in those cases, the Launcher will attempt to resend the command until it works).

[Launcher] Sending 'g' to subprocess...
[UCM Output] 2025-08-28 12:07:38,532 INFO  [default] ack received: 8
[UCM Output] 2025-08-28 12:07:38,628 INFO  [default] app ack received

Known Issues & Future Additions

  • Sometimes the signals are not properly received by the device. If so, the code will report app nak received. The launcher will reattempt up to 3 times, after which it will crash. So far, the only reliable solution is to restart the Pi and the SGD.
  • Signals are only sent when certain outputs are received from the UCM C++ code, typically every 1 minute. When multiple signals are within 60s of each other, sometimes the first signal doesn't get sent. Signals are delayed until the outputs are received, so it may occur up to 60s after when it was initially intended to run.
  • Currently only supports a few CTA-2045A signals.
  • Future work includes adding AdvancedLoadUp and the ability to query the water heater for current status.

Acknowledgements

This software package is based on the water_heaters_testings project by Portland State Power Lab

The CTA-2045 UCM C++ Library was originally developed by EPRI

About

CTA-2045 UCM with a Raspberry Pi

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • C++ 80.8%
  • Makefile 13.1%
  • Python 2.4%
  • CMake 2.1%
  • C 1.2%
  • Shell 0.4%