TCP/JSON I2C relay control service targeting Raspberry Pi 4 (Debian Trixie) with one or more Hats from Sequent Microsystems.
Currently, these three hats are supported.
Sequent Microsystems Solid State 16-relay HAT SKU:SM-I-023 Sixteen Solid State Relays 2A/24V 8-Layer Stackable HAT for Raspberry Pi This is really an 8 relay board configured with two SS relays paired, sharing a common contact. The design allows creating 8 Single Pole, Double Throw (SPDT) type connections using SS relays that are SPST by themselves. You would have to handle toggling them in opposite states to make that happen.
Sequent Microsystems 8-relay HAT SKU: SM-H-002 Eight Relays 4A/120V 8-Layer Stackable HAT for Raspberry Pi
Sequent Microsystems 4-relay HAT SKU: SM-I-010 Four Relays four HV Inputs 8-Layer Stackable HAT for Raspberry Pi
This daemon supports all three of the above hats. Board type is defined using the board configuration key in the config file /etc/PgTgPiSequent/PgTgPiSequent.conf. Although specifically created for use with PgTgBridge and it's built-in plugin PgTgPiGpio. This daemon can be used as a smart wrapper to these relay boards, making them accessible using any application or language that can make TCP connections and send string commands, such as from Node-Red.
Commands are newline-delimited, JSON formatted strings sent over TCP. The connection remains open between commands.
| Direction | Example |
|---|---|
| Set ON | {"cmd":"set","output":"output1","value":1} |
| Set OFF | {"cmd":"set","output":"output2","value":0} |
| Timed ON (30s) | {"cmd":"set","output":"output1","value":30} |
| Read all outputs | {"cmd":"read"} |
| Read all inputs | {"cmd":"read_inputs"} |
| OK (set) | {"status":"ok","output":"output1","value":1} |
| OK (read) | {"status":"ok","outputs":{"output1":1,"output2":0}} |
| OK (read_inputs) | {"status":"ok","inputs":{"input1":0,"input2":1,"input3":0,"input4":1}} |
| Error | {"status":"error","message":"unknown output: output5"} |
| Error (no inputs) | {"status":"error","message":"board does not support inputs"} |
| Value | Behaviour |
|---|---|
0 |
Static OFF — cancels any running timer |
1 |
Static ON — cancels any running timer |
2–999 |
Drives output ON; auto-forces OFF after that many seconds. A new value ≥ 2 before expiry resets the timer. |
On expiry the server sends {"status":"ok","output":"<name>","value":0} on the open connection if a client is connected.
When the PgTgBridge GPIO plugin is configured with an Amp PTT output, it sends value: 15
(not 1) whenever the amplifier PTT is keyed. This starts a 15-second channel watchdog timer on
the service side. PgTgBridge then re-sends value: 15 every 10 seconds to keep the watchdog
alive for the duration of the transmission. When PTT is released the PgTgBridge sends value: 0.
If the PgTgBridge loses connectivity, the watchdog expires after 15 seconds and the PTT output is automatically deactivated — preventing a stuck transmitter if the connectivity to the host machine is lost.
If the PgTgBridge service is stopped, PgTg sends value: 0 to all configured channels before halting.
Enable I2C on the Raspberry Pi (required once):
sudo raspi-config
# Interface Options → I2C → EnableOr add to /boot/firmware/config.txt:
dtparam=i2c_arm=on
Verify the relay board is detected (stack 0 appears at address 0x27):
i2cdetect -y 1Location: /etc/PgTgPiSequent/PgTgPiSequent.conf
# PgTgPiSequent configuration file
# TCP port for the JSON command interface
port = 5556
# Board type: 16relay (default), 8relay, or 4relay
board = 16relay
# Sequent Microsystems relay board stack level (0-7, default 0)
# Stack 0 = I2C address 0x27 (formula: (stack + 0x20) ^ 0x07)
# Verify with: i2cdetect -y 1
stack = 0
# Relay output mappings: output<N> = relay channel number
# 16relay board: channels 1-16
# 8relay board: channels 1-8
# 4relay board: channels 1-4
output1 = 1
output2 = 2
output3 = 3
output4 = 4| Key | Description |
|---|---|
port |
TCP port for the JSON command interface |
board |
16relay (default), 8relay, or 4relay — selects the Sequent HAT |
stack |
Board stack level 0–7 (physical jumper); each stacked board gets a unique level |
output<N> |
Maps logical output N to a relay channel on the board (1–16 for 16relay, 1–8 for 8relay, 1–4 for 4relay) |
input<N> |
(4relay only) Maps logical input N to a digital input channel (1–4) |
The live conf file is created from the package template on first install and is preserved on upgrade and removal. Edit it directly on the Pi; it is never overwritten by apt.
port = 5556
board = 8relay
stack = 0
output1 = 1
output2 = 2
output3 = 3
output4 = 4
output5 = 5
output6 = 6
output7 = 7
output8 = 8port = 5556
board = 4relay
stack = 0
output1 = 1
output2 = 2
output3 = 3
output4 = 4
input1 = 1
input2 = 2
input3 = 3
input4 = 4The service runs as the dedicated system user PgTgPiSequent (member of the i2c group) — no root required.
[Unit]
Description=PgTgPiSequent TCP/JSON I2C relay control service
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=/usr/bin/PgTgPiSequent /etc/PgTgPiSequent/PgTgPiSequent.conf
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=PgTgPiSequent
User=PgTgPiSequent
Group=i2c
[Install]
WantedBy=multi-user.targetThe service file is installed and enabled automatically by the Debian package.
Two build workflows are available — cross-compile from a WSL2 host, or build natively on the Pi. If building under WSL2, a deb package is created.
Prerequisites (install once on the Pi):
sudo apt install cmake ninja-build./build
# Produces: build-native/PgTgPiSequentYou will be responsible for copying the PgTgPiSequent binary to /usr/bin/PgTgPiSequent:
sudo cp build-native/PgTgPiSequent /usr/bin/PgTgPiSequent
sudo chmod +x /usr/bin/PgTgPiSequentAnd creating the configuration file at /etc/PgTgPiSequent/PgTgPiSequent.conf.
(you need to setup the cross-compiler yourself)
Prerequisites (install once in WSL2):
sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu cmake ninja-buildrm -rf build-aarch64 && mkdir build-aarch64
./build-with-cross-compiler
# Produces: build-aarch64/PgTgPiSequent (ELF aarch64)./package
# Produces: PgTgPiSequent_1.0.2_arm64.deb
# Sources binary from build-aarch64/PgTgPiSequent./deploy
# SCPs PgTgPiSequent_1.0.2_arm64.deb to pi@<yourPiIpaddress>:/home/pi/sudo apt install /home/pi/PgTgPiSequent_1.0.2_arm64.debThe package installer:
- Creates the
PgTgPiSequentsystem user and adds it to thei2cgroup - Copies the factory-default config to
/etc/PgTgPiSequent/PgTgPiSequent.conf(first install only) - Copies the daemon binary to
/usr/bin - Installs and starts the systemd service
# Upgrade (live config is preserved)
sudo apt install /home/pi/PgTgPiSequent_1.0.2_arm64.deb
# Remove (binary and service removed; config kept)
sudo apt remove PgTgPiSequent
# Full purge (config and system user also removed)
sudo apt purge PgTgPiSequent# Set output1 ON
echo '{"cmd":"set","output":"output1","value":1}' | nc localhost 5556
# Read all output states
echo '{"cmd":"read"}' | nc localhost 5556
# Set output1 OFF
echo '{"cmd":"set","output":"output1","value":0}' | nc localhost 5556
# Timed ON — output1 goes ON, forces OFF after 30 seconds
echo '{"cmd":"set","output":"output1","value":30}' | nc localhost 5556
# Monitor in journald
journalctl -f -u PgTgPiSequent# Start and follow logs
sudo systemctl start PgTgPiSequent && journalctl -u PgTgPiSequent -f
# Stop (triggers clean I2C release — verify in journal)
sudo systemctl stop PgTgPiSequent
# Confirm service is running as PgTgPiSequent (not root)
ps aux | grep PgTgPiSequent
# See user and group
ps -eo user,group,cmd | grep PgTgPiSequent