Split all site-specific settings (RECIPIENTS, FROM_ADDR, ALERT_SUBJECT, CA_TIMEOUT, MONITORS) out of EPICS2SMS.sh into a separate config file that is sourced at startup, so "git pull" no longer clobbers local settings. - epics2sms.conf is git-ignored (local, per-host). - epics2sms.conf.example is tracked and documents the format. - Config path: first CLI arg > EPICS2SMS_CONF env var > epics2sms.conf beside the script. Missing config or empty RECIPIENTS/MONITORS exits with a clear error pointing at the template. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EPICS2SMS
Monitor one or more EPICS PVs and send an SMS alert via PSI mail infrastructure.
This tool does not use local /usr/sbin/sendmail. It sends mail via direct SMTP
to smtp.psi.ch to ensure the message is handled as a registered
system/application sender.
Files
-
epics2sms.sh
Runs one or more independent monitors, each polling a PV, keeping a moving average, and sending SMS/mail when the average crosses a directional threshold. -
smtp_send.py
SMTP transport helper (no authentication). Sets both headerFrom:and envelope sender (MAIL FROM) to the configured sender address.
Monitors
Each monitor is one pipe-separated entry in the MONITORS array:
pv | dir | threshold | poll_s | alarm_poll_s | n_avg | n_msg | msg_delay_s | text
| Field | Meaning |
|---|---|
pv |
EPICS PV name |
dir |
alarm direction: lt (avg < threshold) or gt (avg > threshold) |
threshold |
numeric threshold |
poll_s |
seconds between polls while in normal state |
alarm_poll_s |
seconds between polls while in alarm (how often the average is refreshed and recovery is checked) |
n_avg |
samples averaged before an alarm can fire ("N Mittel") |
n_msg |
max messages per alarm episode, then silent ("N Messages") |
msg_delay_s |
minimum seconds between two alarm messages; polling keeps running faster, but messages are throttled to this spacing (the first message of an episode goes out immediately) |
text |
message text, also the start of the SMS body |
Multiple monitors may watch the same PV with different thresholds and timing; each runs as its own background loop with independent state.
Example (current config):
MONITORS=(
"X12SA-OP-CC:L1Level_MON|lt|55|60|60|4|10|300|X12SA-OP-CC:L1Level_MON <55%"
"X12SA-OP-CC:L1Level_MON|gt|75|10|10|4|10|300|X12SA-OP-CC:L1Level_MON >75%"
)
On startup, the script sends one brief notification to all recipients listing the monitors it is watching (PV, threshold, timing) so you can confirm it is running. This is best-effort: if it fails to send, monitoring still starts.
Behaviour of one monitor:
- polls the PV every
poll_sseconds while normal, everyalarm_poll_swhile in alarm - keeps a moving average of the last
n_avgsamples; an alarm can only fire once the window is full, so a single spurious reading cannot trigger it - while the average is in alarm, sends the first message immediately, then up
to
n_msgmessages total, spaced at leastmsg_delay_sapart, then stays silent - once the average returns to normal, it resets the message counter and — if at least one alarm message was sent this episode — sends one recovery ("RESOLVED") message
- unreadable / non-numeric reads are logged and skipped (they do not enter the average and never trigger an alarm)
Why SMTP instead of sendmail?
On beamline console hosts, local sendmail may be routed through internal relays
or firewall rules and can lead to silent drops for mail-to-SMS gateways.
Direct SMTP to smtp.psi.ch makes the transport path explicit and reproducible.
Requirements
- EPICS CA tools available on the host (
caget). - Python 3 available (
python3). - Network access from the host to
smtp.psi.ch:25.
Configuration
All site-specific settings live in an untracked config file, so
git pull never touches them. Copy the template once and edit it:
cp epics2sms.conf.example epics2sms.conf
$EDITOR epics2sms.conf
epics2sms.conf is git-ignored; epics2sms.conf.example is tracked and
documents the format. The config file is sourced as bash and may set:
MONITORS
One entry per monitor (see Monitors above).RECIPIENTS
Applied to every monitor. Include the SMS gateway address, e.g.:0041797554007@sms.switch.ch079XXXXXXX@mail2sms.swisscom.com
FROM_ADDR
Must be a registered PSI system/application sender, e.g.cSAXS@psi.ch.ALERT_SUBJECT
Subject used for alert mails/SMS.CA_TIMEOUT
Channel Access timeout (caget -w) in seconds. Thecagetdefault (~1 s) can be too short for the first connection to a PV, which then looks like "not connected"; keep this well below the shortest poll interval.
FROM_ADDR is critical: messages from host/user addresses like
e23080@x12sa-cons-02.psi.ch may be filtered and never reach the SMS gateway.
By default the config is read from epics2sms.conf next to the script;
override the path with the EPICS2SMS_CONF environment variable or the first
command-line argument (./EPICS2SMS.sh /path/to/other.conf).
Quick test
Send a normal email:
python3 smtp_send.py --to andreas.menzel@psi.ch --from-addr cSAXS@psi.ch "Test $(date)"
Send an SMS (via mail2sms):
python3 smtp_send.py --to 079XXXXXXX@mail2sms.swisscom.com --from-addr cSAXS@psi.ch "SMS test $(date)"
Run the monitor
./epics2sms.sh
All monitors run in one process; Ctrl-C (or SIGTERM) stops them together.
Notes / Troubleshooting
- If no SMS arrives but SMTP returns success, ask IT to check Exchange/relay transport rules for the registered sender and the mail2sms gateway domain.
- Use
smtp_send.pydirectly for transport debugging (it should return non-zero on errors).