Graham Eddy

weewx Server (multiple instances)

Install, configure and manage multiple instances of weewx using systemd.

2022-03-26 Raspbian buster


This is a guide to setting up multiple instances of weewx on a single Debian server using systemd. The reader is expected to be linux literate.

More accurately, it is a cookbook on how I configure my host to run separate instances of weewx to:

There are several additional requirements that I implement that influence my implementation:


Installation

graham:~ sudo apt update graham:~ sudo apt install python3-configobj python3-pil python3-serial \ python3-usb python3-pip python3-cheetah python3-ephem graham:~ wget https://weewx.com/downloads/weewx-4.8.0.tar.gz graham:~ wget https://github.com/gjr80/weewx-gw1000/releases/tag/v0.4.2/gw1000-0.4.2.tar.gz graham:~ sudo adduser weewx # owner of code, instances and processes graham:~ sudo mkdir ~weewx/public_html # ramdisk for generated reports graham:~ sudo chown weewx:weewx ~weewx/public_html graham:~ sudo vi /etc/fstab # mount ramdisk on reboot
/etc/fstab append to end of file
tmpfs /home/weewx/public_html tmpfs rw,nodev,nosuid,noatime,noexec,uid=weewx,gid=weewx,mode=0775,size=10M
graham:~ sudo mount -a # mount ramdisk now graham:~ mount | grep tmpfs tmpfs on /run type tmpfs (rw,nosuid,nodev,size=1600104k,nr_inodes=819200,mode=755) tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,size=2097152k) tmpfs on /home/weewx/public_html type tmpfs (rw,nosuid,nodev,noexec,noatime,size=10240k,mode=775,uid=1002,gid=1002) graham:~ sudo systemctl disable dphys-swapfile # do not enable swap on reboot graham:~ sudo dphys-swapfile uninstall # remove current swap file graham:~ free -m total used free shared buff/cache available Mem: 7812 213 5098 3 2500 7473 Swap: 0 0 0 graham:~ sudo -u weewx -i # change to owner of code, etc weewx:~ cd /tmp weewx:/tmp tar xvf ~graham/weewx-4.8.0.tar.gz weewx:/tmp cd weewx-4.8.0 weewx:/tmp/weewx-4.8.0 python3 setup.py build weewx:/tmp/weewx-4.8.0 python3 setup.py install # installation not as 'root'!! weewx:/tmp/weewx-4.8.0 cd weewx:~ rm -r /tmp/weewx-4.8.0 weewx:~ mv weewx.conf weewx.conf-dist # save as instance config template weewx:~ exit

Base configuration to support weewx instances

Although all instances run from the same codebase, we keep individual state in files named after the instance inst:

~weewx/inst.conf
instance configuration, based upon saved weewx.conf-dist
~weewx/archive/inst.sdb
instance database
~weewx/skins/inst/
instance skin template files, based upon provided Seasons skin for the purpose of this document
~weewx/public_html/inst/
instance report files generated at run-time
/var/log/weewx/inst.log
instance log
/run/weewx/inst.pid
instance PID file

Note that we will designate one weewx instance as the producer of the official, consolidated report, but the other instances will produce smaller reports more specific to them.

For the systemd services, think of weewx@ as a class and weewx@foo as an instance of that class. We install file weewx@.service to create the class as part of our systemd configuration; we will create instances later.

graham:~ cp ~weewx/util/systemd/weewx.service /tmp/weewx@.service graham:~ vi /tmp/weewx@.service # weewx service class definition
/tmp/weewx@.service make it look as follows
# systemd weewx (unit instance)
#   pid:                        /run/weewx/%i.pid
#   log-label (programname):    weewx-%i
#   conf:                       /home/weewx/%i.conf

[Unit]
Description=weewx weather system (%I)
Requires=time-sync.target
After=time-sync.target
RequiresMountsFor=/home

[Service]
ExecStart=/home/weewx/bin/weewxd --daemon --pidfile=/run/weewx/%i.pid --log-label=weewx-%i /home/weewx/%i.conf
ExecReload=/bin/kill -HUP $MAINPID
Type=forking
PIDFile=/run/weewx/%i.pid
User=weewx
Group=weewx
# workaround to stop SIGKILL sent instantly (systemd bug)
SendSIGKILL=no

[Install]
WantedBy=multi-user.target
# no default instance
#DefaultInstance=
graham:~ sudo cp /tmp/weewx@.service /etc/systemd/system/ graham:~ sudo systemctl daemon-reload graham:~ rm /tmp/weewx@.service graham:~ sudo mkdir /run/weewx # container for instance run environments graham:~ sudo chown weewx:weewx /run/weewx graham:~ sudo chmod 755 /run/weewx graham:~ sudo vi /etc/tmpfiles.d/weewx.conf
/etc/tmpfiles.d/weewx.conf new file
#type path            mode user  group age arg
d     /run/weewx      0755 weewx weewx -
graham:~ sudo cp ~weewx/util/rsyslog.d/weewx.conf /etc/rsyslog.d/ graham:~ sudo vi /etc/rsyslog.d/weewx.conf
/etc/rsyslog.d/weewx.conf make it look as follows
# rsyslog weewx

# weewx default
:programname,startswith,"weewx" /var/log/weewx/weewx.log
:programname,startswith,"weewx" stop

# weewx utilities
:programname,startswith,"wee_" /var/log/weewx/weewx.log
:programname,startswith,"wee_" stop
graham:~ sudo cp ~weewx/util/logrotate.d/weewx /etc/logrotate.d/ graham:~ sudo vi /etc/logrotate.d/weewx
/etc/logrotate.d/weewx make it look as follows
# logrotate weewx

/var/log/weewx/weewx.log
{
  create 640 weewx adm
  daily
  missingok
  rotate 7
  compress
  delaycompress
  notifempty
  maxsize=10M
  sharedscripts
  postrotate
    /usr/bin/killall -HUP rsyslogd
  endscript
}
graham:~ sudo mkdir /var/log/weewx # container for instance logs graham:~ sudo chown weewx:adm /var/log/weewx graham:~ sudo chmod 775 /var/log/weewx graham:~ sudo systemctl restart rsyslog

First weewx instance: vp2 collector

graham:~ sudo -u weewx -i # owner of weewx data weewx:~ cp weewx.conf-dist vp2.conf # start with instance config template

skin

weewx:~ vi vp2.conf
~weewx/vp2.conf disable SeasonsReport and insert vp2Report before it
    [[vp2Report]]             # optional for collector
        # skin for the vp2 instance
        skin = vp2
        enable = true         # enable vp2 custom report
        HTML_ROOT = public_html/vp2  # subdir

    [[SeasonsReport]]
        # The SeasonsReport uses the 'Seasons' skin, which contains the
        # images, templates and plots for the report.
        skin = Seasons
        enable = false        # disable standard report
weewx:~ cp -r skins/Seasons skins/vp2 # start from Seasons as template skin weewx:~ vi skins/vp2/*

database

weewx:~ vi vp2.conf
~weewx/vp2.conf change database name
    [[archive_sqlite]]
        database_name = vp2.sdb
        database_type = SQLite

The database is automatically created when instance first runs.

driver

weewx:~ wee_config --config=vp2.conf --reconfigure

log

weewx:~ vi vp2.conf
~weewx/vp2.conf set debug level
debug = 3
weewx:~ exit # good practice: 'weewx' doesn't sudo graham:~ sudo vi /etc/rsyslog.d/weewx.conf
/etc/rsyslog.d/weewx.conf insert vp2 lines near start of file
# rsyslog weewx

# weewx vp2 collector
:programname,isequal,"weewx-vp2" /var/log/weewx/vp2.log
:programname,isequal,"weewx-vp2" stop

# weewx default
graham:~ sudo vi /etc/logrotate.d/weewx
/etc/logrotate.d/weewx insert vp2 log reference – note the trailing backslash)
# logrotate weewx

/var/log/weewx/vp2.log \
/var/log/weewx/weewx.log
{
  create 640 weewx adm
graham:~ sudo systemctl restart rsyslog

start/stop

graham:~ sudo systemctl enable weewx@vp2 # 'create' instance (start after each reboot) graham:~ sudo systemctl start weewx@vp2 # start instance now graham:~ sudo systemctl status weewx@vp2 graham:~ tail -f /var/log/weewx/vp2.log graham:~ ls ~weewx/public_html/vp2 celestial.html monthrx.png weektempdew.png daybarometer.png monthtempdew.png weektempfeel.png dayhum.png monthtempfeel.png weektempin.png dayhumin.png monthtempin.png weektemp.png dayrain.png monthtemp.png weekvolt.png dayrx.png monthvolt.png weekwind.png daytemp.png monthwind.png weekwinddir.png daytempdew.png monthwinddir.png weekwindvec.png daytempfeel.png monthwindvec.png yearbarometer.png daytempin.png NOAA/ yearhum.png dayvolt.png rss.xml yearhumin.png daywind.png seasons.css yearrain.png daywinddir.png seasons.js yearrx.png daywindvec.png statistics.html yeartempdew.png favicon.ico tabular.html yeartempfeel.png font/ telemetry.html yeartempin.png index.html weekbarometer.png yeartemp.png monthbarometer.png weekhum.png yearvolt.png monthhum.png weekhumin.png yearwind.png monthhumin.png weekrain.png yearwinddir.png monthrain.png weekrx.png yearwindvec.png

Web-browsing to the public_html/vp2/ content is outside scope of this document.

The vp2 instance can be stopped by:

graham:~ sudo systemctl stop weewx@vp2 # stop instance now graham:~ sudo systemctl disable weewx@vp2 # 'delete' instance (not restart after reboot)

Second weewx instance: gw1000 (aka ecowitt) collector

graham:~ sudo -u weewx -i weewx:~ cp weewx.conf-dist gw1000.conf # start from instance config template

skin

weewx:~ vi gw1000.conf
~weewx/gw1000.conf disable SeasonsReport and insert gw1000Report before
    [[gw1000Report]]          # optional for collector
        # skin for the gw1000 instance
        skin = gw1000
        enable = true         # enable gw1000 custom report
        HTML_ROOT = public_html/gw1000  # subdir

    [[SeasonsReport]]
        # The SeasonsReport uses the 'Seasons' skin, which contains the
        # images, templates and plots for the report.
        skin = Seasons
        enable = false        # disable standard report
weewx:~ cp -r skins/Seasons skins/gw1000 # start from Seasons as template skin weewx:~ vi skins/gw1000/*

database

weewx:~ vi gw1000.conf
~weewx/gw1000.conf change database name
    [[archive_sqlite]]
        database_name = gw1000.sdb
        database_type = SQLite

driver

Unlike Vantage driver, which is part of the weewx distribution, GW1000 driver is an extension. We downloaded it earlier.

weewx:~ wee_extension --config=gw1000.conf --install=/home/graham/gw1000-0.4.1.tar.gz weewx:~ wee_config --config=gw1000.conf --reconfigure weewx:~ vi gw1000.conf # craft further driver details

log

weewx:~ vi gw1000.conf
~weewx/gw1000.conf set debug level
debug = 3
weewx:~ exit # good practice: 'weewx' doesn't sudo graham:~ sudo vi /etc/rsyslog.d/weewx.conf
/etc/rsyslog.d/weewx.conf insert gw1000 log stanza
# rsyslog weewx

# weewx gw1000 collector
:programname,isequal,"weewx-gw1000" /var/log/weewx/gw1000.log
:programname,isequal,"weewx-gw1000" stop

# weewx vp2 collector
graham:~ sudo vi /etc/logrotate.d/weewx
/etc/logrotate.d/weewx insert gw1000 log reference – note trailing slash
# logrotate weewx

/var/log/weewx/gw1000.log \
/var/log/weewx/vp2.log \
/var/log/weewx/weewx.log
graham:~ sudo systemctl restart rsyslog

start/stop

graham:~ sudo systemctl enable weewx@gw1000 # 'create' instance (start after each reboot) graham:~ sudo systemctl start weewx@gw1000 # start instance now graham:~ sudo systemctl status weewx@gw1000 graham:~ tail -f /var/log/weewx/gw1000.log graham:~ ls ~weewx/public_html/gw1000

The instance can be stopped by:

graham:~ sudo systemctl stop weewx@gw1000 # stop instance now graham:~ sudo systemctl disable weewx@gw1000 # 'delete' instance (not restart after reboot)

Third weewx instance: editor aggregator

This instance is primarily to produce the official, consolidated report for public consumption on website. It collates data from the collector weewx instances and perhaps date from other sources such as forecast or minor inputs too small to warrant their own collector instance.

This report draws from the databases of several weewx instances:

gw1000_binding
gw1000 instance database;
vp2_binding
vp2 instance database;
wx_binding
editor instance database – this one, the default binding wx_binding
graham:~ sudo -u weewx -i weewx:~ cp weewx.conf-dist editor.conf # start from instance config template

skin

weewx:~ vi editor.conf
~weewx/editor.conf disable SeasonsReport and insert editorReport before
    [[editorReport]]          # raison d'etre for this aggregator
        # skin for the editor instance
        skin = editor
        enable = true         # enable editor custom report
        HTML_ROOT = public_html   # not in a subdir

    [[SeasonsReport]]
        # The SeasonsReport uses the 'Seasons' skin, which contains the
        # images, templates and plots for the report.
        skin = Seasons
        enable = false        # disable standard report
weewx:~ cp -r skins/Seasons skins/editor # start from Seasons as template skin weewx:~ vi skins/editor/*

Details of skin and report customisation out of scope for this document.

databases

weewx:~ vi editor.conf
~weewx/editor.conf update all database names
    [[archive_sqlite]]
        database_name = editor.sdb
        database_type = SQLite
    [[gw1000_sqlite]]
        database_name = gw1000.sdb
        database_type = SQLite
    [[vp2_sqlite]]
        database_name = vp2.sdb
        database_type = SQLite
update all database bindings
   [[wx_binding]]
        # The database must match one of the sections in [Databases].
        # This is likely to be the only option you would want to change.
        database = archive_sqlite
        # The name of the table within the database
        table_name = archive
        # The manager handles aggregation of data for historical summaries
        manager = weewx.manager.DaySummaryManager
        # The schema defines the structure of the database.
        # It is *only* used when the database is created.
        schema = schemas.wview_extended.schema
    [[gw1000_binding]]
        manager = weewx.manager.Manager
        schema = schemas.wview_extended.schema
        table_name = archive
        database = gw1000_sqlite
    [[vp2_binding]]
        manager = weewx.manager.Manager
        schema = schemas.wview_extended.schema
        table_name = archive
        database = vp2_sqlite

Driver

Ultimately, something must be injecting observations into the weewx instance to keep it turning over, though this is independent of the archive interval at the end of each of which the reports are generated. This can be either a simple subsidiary input with its own driver, or the reporter instance can be merged into one of the collector instances.

log

weewx:~ vi editor.conf
~weewx/editor.conf set debug level
debug = 3
weewx:~ exit # good practice: 'weewx' doesn't sudo graham:~ sudo vi /etc/rsyslog.d/weewx.conf
/etc/rsyslog.d/weewx.conf insert editor log stanza)
# rsyslog weewx

# weewx editor reporter
:programname,isequal,"weewx-editor" /var/log/weewx/editor.log
:programname,isequal,"weewx-editor" stop

# weewx gw1000 collector
graham:~ sudo vi /etc/logrotate.d/weewx
/etc/logrotate.d/weewx insert editor log reference – note trailing slash
# logrotate weewx

/var/log/weewx/editor.log \
/var/log/weewx/gw1000.log \
graham:~ sudo systemctl restart rsyslog

start/stop

graham:~ sudo systemctl enable weewx@editor # 'create' instance (start after each reboot) graham:~ sudo systemctl start weewx@editor # start instance now graham:~ sudo systemctl status weewx@editor graham:~ tail -f /var/log/weewx/editor.log graham:~ ls ~weewx/public_html

The instance can be stopped by:

graham:~ sudo systemctl stop weewx@editor # stop it now graham:~ sudo systemctl disable weewx@editor # 'delete' instance (not start after reboot)

Finally

Operationally, the weewx collector and aggregator instances can be started and stopped independently.

Semantically, the aggregator instance depends upon sufficiently current data being available in the collector instances databases, so be wary of keeping collectors offline for long while aggregator(s) are running.