superweatherdaemon Documentation
Overview
superweatherdaemon is a weather monitoring daemon designed for astronomical observatories. It collects data from multiple heterogeneous weather stations (meteostations) via a plugin architecture, computes a unified weather status, and provides control interfaces over TCP and local UNIX sockets. The daemon can issue warnings, change weather level, and even trigger a forced shutdown of instruments (e.g., close dome) when conditions become dangerous.
The project is written in C, uses CMake as its build system, and relies on the usefull_macros library for utilities and socket management.
Dependencies
- Build tools: CMake >= 4.0, C compiler with C11 support,
pkg-config. - Library:
usefull_macros>= 0.3.5 (sl_*functions for logging, sockets, command-line parsing, etc.). - Optional:
net-snmp(for the SNMP UPS plugin).
On Gentoo/Calculate Linux, install the basic build dependencies:
emerge dev-build/cmake dev-util/pkgconf
# usefull_macros must be installed from its own source; follow its documentation.
# For SNMP support:
emerge net-analyzer/net-snmp
Building and Installation
-
Clone or download the source tree.
-
Create a build directory and run CMake:
mkdir build && cd build cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -
Customise enabled plugins with
-Doptions (all areONby default):cmake .. -DDUMMY=OFF -DFDEXAMPLE=OFF -DHYDREON=ON -DBTAMETEO=ON ...Available plugin options:
DUMMYDummy weather station for testing.FDEXAMPLEExample file descriptor plugin.HYDREONHydreon RG-11 rain sensor.BTAMETEOBTA 6-m telescope main meteostation (shared memory).REINHARDTOld Reinhardt meteostation.WXA100Vaisala WXA100 ultrasonic station.SNMPUPS monitoring via SNMP.LIGHTNINGAS3935-based lightning sensor.
-
Building:
make su -c "make install"The main executable
superweatherdaemonis installed intobin; the plugin shared libraries (lib*.so) go to the library directory.
Configuration
The daemon can be configured entirely via command-line options, a configuration file, or both. Command-line options take precedence.
Command-line Options
| Option | Description |
|---|---|
-h, --help |
Show help message and exit. |
-c <file>, --conffile <file> |
Use a configuration file. Point non-existant file to get help. |
-l <path>, --logfile=<path> |
Write logs to a file (default: none). |
-P <path>, --pidfile=<path> |
PID file (default /tmp/superweatherdaemon.pid). |
-p <spec>, --plugin=<spec> |
Add a weather plugin; can be repeated for different plugins. Format: path:type:device (see below). |
--port=<node> |
Network port for clients (default 12345). Use localhost:port for local access only. |
--sockpath=<path> |
UNIX socket path (start with @ for an abstract socket). |
-T <seconds>, --pollt <seconds> |
Max polling interval in seconds (integer). |
-v, --verb |
Increase verbosity level (each -v adds 1). |
Plugin Specification
A plugin is a shared library (.so) that provides a sensor_init function. It is loaded with the
--plugin option.
Format:
--plugin=library:type:parameter
library: path to the shared library, e.g.libwxa100.so.type: Connection typeDfor serial device,Ufor UNIX socket,Nfor INET socket.parameter: device path and optional speed (/dev/ttyS0:9600), UNIX socket name, orhost:portfor INET.
Examples:
--plugin=libreinhardt.so:D:/dev/ttyS0
--plugin=libwxa100.so:D:/dev/pl2303_0
--plugin=libhydreon.so:D:/dev/ch340_0:1200
--plugin=libbtameteo.so (no device, uses shared memory)
Multiple plugins are listed in order of importance (first ones are considered primary for weather level calculation).
Configuration File
The configuration file uses a simple key = value syntax, with # for comments. Example:
# network port for clients
port = 4444
logfile = /var/log/meteo/superweather.log
verbose = 2
sockpath = "@weather"
pollt = 1
reinit_delay = 10
# Weather thresholds
ahtung_delay = 1800 # in seconds
good_wind = 5.0 # m/s
bad_wind = 10.0
terrible_wind = 15.0
good_humidity = 65.0 # percents
bad_humidity = 87.0
terrible_humidity = 94.0
good_clouds = 2500.0 # for reinhardt sensor in its units
bad_clouds = 2000.0
terrible_clouds = 500.0
clouds_negflag = 1 # 1 means the higher the value the better
good_sky = -40.0 # sky minus ambient temperature, degC
bad_sky = -10.0
terrible_sky = 0.0
# plugins - most important first
plugin = libwxa100.so:D:/dev/pl2303_0
plugin = libhydreon.so:D:/dev/ch340_0:1200
plugin = libbtameteo.so
plugin = libreinhardt.so:D:/dev/ttyS0
Run with:
superweatherdaemon -c /etc/weather.conf
To run on system start you can use OpenRó rc.local mechanism.
Plugins
Each weather station is implemented as a shared library exporting a single function:
int sensor_init(sensordata_t *s);
The sensordata_t structure contains all required callbacks, data pointers, and private fields.
See weathlib.h for the full definition.
Plugin Lifecycle
- Loading: The main daemon calls
s = sensor_new(...)to createsensordata_tstructure, opens given library withdlopenand callssensor_initon that news. - Initialisation:
- Set
s->name,s->Nvalues,s->valuesarray. - Configure the communication channel (file descriptor) using
getFD(s->path). - Create a worker thread that periodically reads sensor data and updates
s->values. Don't forget to locks->valmutexon any operation withs->values.
- Set
- Data delivery: Each time new data is available, call
s->freshdatahandler(s)(this is set by the daemon todumpsensors). The main daemon then merges the data into the global weather evaluation. - Shutdown: The daemon calls
s->kill(s), which must join the thread, close the file descriptor, and free resources. Defaultcommon_killhandles most of this; plugins can override it.
If the plugin is disconnected for some reason (for example, the network connection is lost), the
daemon will try to reconnect every reinit_delay seconds.
Available Plugins
| Library | Sensor | Type |
|---|---|---|
libwsdummy.so |
Dummy station outputs random walk data around realistic values. | Test / Development |
libfdex.so |
Example of a filedescriptor based plugin. Prompts for commaseparated values. | Example |
libhydreon.so |
Hydreon RG-11 optical rain sensor. | Serial |
libbtameteo.so |
BTA 6-m telescope main meteostation (shared memory). | Shared Memory |
libreinhardt.so |
Old Reinhardt meteostation (serial, ?U command). |
Serial |
libwxa100.so |
Vaisala WXA100 ultrasonic meteostation (serial, 0R0 command). |
Serial |
libsnmp.so |
UPS monitor via SNMP (requires net-snmp). | Network |
liblightning.so |
AS3935-based lightning sensor (serial). | Serial |
Writing a New Plugin
Use the existing plugins as templates. A minimal plugin must:
- Include
weathlib.h. - Define an array of
val_tdescribing each measured quantity. - Implement
sensor_init:- Allocate
s->values, copy the template array. - Set
s->Nvalues,s->name. - Open the device (use
getFD(s->path)for serial/sockets) and sets->fdes. If your plugin don't need file descriptor, you must sets->fdesto any non-negative value. - Create a ring buffer if needed (
sl_RB_new). - Start the worker thread that reads data, updates values inside
pthread_mutex_lock(&s->valmutex), and callss->freshdatahandler(s)(outside mutex locked). - Return
TRUEon success,FALSEon failure (calls->kill(s)to clean up).
- Allocate
- The
weathlib.hprovides helper functions:common_onrefresh,common_getval,common_kill.
Weather Level Calculation
The daemon combines data from all active plugins and continuously evaluates a global weather level:
0GOOD: observations can start safely.1BAD: risky to start, but can continue.2TERRIBLE: dome must close, instruments park.3PROHIBITED: complete shutdown, power off equipment.
Criteria
Each weather parameter (wind speed, humidity, clouds, sky temperature, lightning distance, precipitation, etc.) has configurable thresholds:
goodbelow/above this (depending on sign) the condition is good.badabove this the condition is bad.terribleabove this the condition is terrible.prohibited(if defined) above this the condition goes directly to PROHIBITED.negflagif1, a smaller value is worse (e.g., clouds).shtdnflagif1, entering the terrible/prohibited range also sets the FORCE SHUTDOWN flag.
Special Flags
- FORCE SHUTDOWN: Some parameters (e.g., lightning within <= 5km, UPS on battery) carry the
IS_FORCEDSHTDNmeaning and haveshtdnflag = 1. When their value exceeds the terrible threshold, the forced shutdown flag is raised, which immediately sets the weather level to PROHIBITED and is typically used to cut power. - Manual FORBID: An operator can send a signal (
SIGUSR1) or a socket command to forbid observations, which also forces PROHIBITED.SIGUSR2or a socket command clears forbidden flag.
Hysteresis
Once a bad/terrible state is reached, the level is not lowered until ahtung_delay seconds have
passed since the last serious event. This prevents rapid toggling.
Server Commands (Socket API)
The daemon listens on two interfaces:
- Network socket (TCP, default port 12345) read-only (in meaning they cannot change any parameters) access for remote clients.
- Local UNIX socket (abstract or filesystem, default
@weather) full control for local applications.
Commands are sent as plain text strings, terminated by a newline.
Common (read-only) Commands
| Command | Description |
|---|---|
get |
Return all collected weather data (all stations). |
get=<N> |
Return data from plugin <N>. |
list |
List all loaded plugins with their names and value counts. |
time |
Return server UNIX time (float seconds). |
chklevel |
Show the sense (importance) level of every collected parameter. |
chklevel=<N> |
Same for a specific plugin. |
Local-only (read-write) Commands
| Command | Description |
|---|---|
forbid |
Get current FORBID flag (0/1). |
forbid=<0/1> |
Set/clear manual FORBID. |
forceoff |
Get FORCE SHUTDOWN flag. |
forceoff=<0/1> |
Set/clear it manually. |
weathlevel |
Get current weather level (0-3 for GOOD-PROHIBITED). |
weathlevel=<0..3> |
Force weather level (use with caution). |
setlevel=<plugin>:<param>=<sense>,... |
Change the sense field of one or more sensor parameters. Example: setlevel=1:WIND=3,HUMIDITY=3 disables wind and humidity from station 1. |
mute=<N> |
Stop refreshing data from plugin <N> (mute). |
unmute=<N> |
Resume refreshing. |
ismuted=<N> |
Return 1 if muted, 0 otherwise. |
Reply format: each line is a FITS-like KEY = value / comment string; commands that set something
usually echo back the variable and its new value. For get=<N> each KEY have a suffix in square
brackets number of plugin, e.g. WIND[1]= 10.1 / Wind speed, m/s.
Signals
| Signal | Effect |
|---|---|
SIGTERM, SIGINT, SIGQUIT |
Clean shutdown (removes PID file, kills plugins, destroys sockets). |
SIGHUP |
Ignored. |
SIGUSR1 |
Set manual FORBID (weather level == PROHIBITED). |
SIGUSR2 |
Clear manual FORBID. |
SIGPIPE |
Logged, used to detect network plugins disconnections. |
Files
| File | Purpose |
|---|---|
CMakeLists.txt |
Top-level build definition. |
cmdlnopts.c/.h |
Command-line and configuration file parsing. |
main.c |
Daemon entry point, signal handlers, forking. |
mainweather.c/.h |
Global weather evaluation, data collection, forced shutdown. |
sensors.c/.h |
Plugin management (load, unload, getters). |
server.c/.h |
TCP and UNIX socket servers. |
weathlib.c/.h |
Common plugin API, value definitions, helper functions. |
fd.c |
Function getFD() to open serial devices or sockets for plugins. |
example.config |
Sample configuration file. |
plugins/CMakeLists.txt |
Build file for all plugins. |
plugins/*.c |
Individual plugin source files. |
License
The project is released under the GNU General Public License v3.0 or later. See the headers in the source files for the full legal text.
For further assistance or to report issues, please contact the maintainer: Edward V. Emelianov edward.emelianoff@gmail.com.