<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://217.79.180.177/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Uwe</id>
	<title>Aquarium-Control - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://217.79.180.177/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Uwe"/>
	<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php/Special:Contributions/Uwe"/>
	<updated>2026-04-05T18:55:19Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=440</id>
		<title>Automatic start by using systemd</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=440"/>
		<updated>2026-02-17T17:50:42Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Configuration of automatic start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Content of the startup script ==&lt;br /&gt;
The shell script for startup of the control application (&amp;lt;code&amp;gt;/usr/local/bin/aquarium_control_startup&amp;lt;/code&amp;gt;) has the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It resets any PID in the lock file from previously instances which were potentially not shut down correctly (for example, in case of power failure).&lt;br /&gt;
It creates the message queue file which is not a file on the hard drive and sets permission accordingly.&lt;br /&gt;
Finally, it starts the control application in the background.&lt;br /&gt;
&lt;br /&gt;
== Configuration of automatic start ==&lt;br /&gt;
The content of systemd unit file &amp;lt;code&amp;gt;/lib/systemd/system/aquarium_control.service&amp;lt;/code&amp;gt; as following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
&lt;br /&gt;
Description=Aquarium Control Application&lt;br /&gt;
&lt;br /&gt;
After=multi-user.target&lt;br /&gt;
&lt;br /&gt;
After=network-online.target time-sync.target&lt;br /&gt;
Wants=network-online.target time-sync.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
&lt;br /&gt;
Type=forking&lt;br /&gt;
&lt;br /&gt;
ExecStart=bash /usr/local/bin/aquarium_control_startup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upon creation/modification of the unit file, one must run the command &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt; in order to activate the changes.&lt;br /&gt;
&lt;br /&gt;
For starting the control application manually via systemd, one can use the command &amp;lt;code&amp;gt;sudo systemctl start aquarium_control_startup.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note: Waiting for the NTP before starting the application will avoid a wrong timestamp occurring, but may inhibit the start of the application if the internet connectivity is gone.&lt;br /&gt;
&lt;br /&gt;
== Creating message queues for operation or test of aquarium_control ==&lt;br /&gt;
The startup script contains the creation of a set of message queues:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one of the message queues is required for operating the control application. The other message queues are use for parallel SW unit testing.&lt;br /&gt;
&lt;br /&gt;
== Initialize lock file with zero as PID ==&lt;br /&gt;
The startup script contains the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lock file has to be initialised to contain zero upon restart of the server. A missing or empty lock file is interpreted by the control application that something has gone wrong and startup will be aborted. In case of uncontrolled shutdown (e.g. power failure), the PID of the last operation may still be in the lock file, hence a reset to zero is required for this case.&lt;br /&gt;
&lt;br /&gt;
== Start the application to run in the background ==&lt;br /&gt;
The start of the application in the background is triggered with the following command:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=439</id>
		<title>Automatic start by using systemd</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=439"/>
		<updated>2026-02-17T17:49:34Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Configuration of automatic start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Content of the startup script ==&lt;br /&gt;
The shell script for startup of the control application (&amp;lt;code&amp;gt;/usr/local/bin/aquarium_control_startup&amp;lt;/code&amp;gt;) has the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It resets any PID in the lock file from previously instances which were potentially not shut down correctly (for example, in case of power failure).&lt;br /&gt;
It creates the message queue file which is not a file on the hard drive and sets permission accordingly.&lt;br /&gt;
Finally, it starts the control application in the background.&lt;br /&gt;
&lt;br /&gt;
== Configuration of automatic start ==&lt;br /&gt;
The content of systemd unit file &amp;lt;code&amp;gt;/lib/systemd/system/aquarium_control.service&amp;lt;/code&amp;gt; as following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
&lt;br /&gt;
Description=Aquarium Control Application&lt;br /&gt;
&lt;br /&gt;
After=multi-user.target&lt;br /&gt;
&lt;br /&gt;
After=network-online.target time-sync.target&lt;br /&gt;
Wants=network-online.target time-sync.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
&lt;br /&gt;
Type=forking&lt;br /&gt;
&lt;br /&gt;
ExecStart=bash /usr/local/bin/aquarium_control_startup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upon creation/modification of the unit file, one must run the command &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt; in order to activate the changes.&lt;br /&gt;
&lt;br /&gt;
For starting the control application manually via systemd, one can use the command &amp;lt;code&amp;gt;sudo systemctl start aquarium_control_startup.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Creating message queues for operation or test of aquarium_control ==&lt;br /&gt;
The startup script contains the creation of a set of message queues:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one of the message queues is required for operating the control application. The other message queues are use for parallel SW unit testing.&lt;br /&gt;
&lt;br /&gt;
== Initialize lock file with zero as PID ==&lt;br /&gt;
The startup script contains the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lock file has to be initialised to contain zero upon restart of the server. A missing or empty lock file is interpreted by the control application that something has gone wrong and startup will be aborted. In case of uncontrolled shutdown (e.g. power failure), the PID of the last operation may still be in the lock file, hence a reset to zero is required for this case.&lt;br /&gt;
&lt;br /&gt;
== Start the application to run in the background ==&lt;br /&gt;
The start of the application in the background is triggered with the following command:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=438</id>
		<title>Automatic start by using systemd</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=438"/>
		<updated>2026-02-17T17:49:25Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Configuration of automatic start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Content of the startup script ==&lt;br /&gt;
The shell script for startup of the control application (&amp;lt;code&amp;gt;/usr/local/bin/aquarium_control_startup&amp;lt;/code&amp;gt;) has the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It resets any PID in the lock file from previously instances which were potentially not shut down correctly (for example, in case of power failure).&lt;br /&gt;
It creates the message queue file which is not a file on the hard drive and sets permission accordingly.&lt;br /&gt;
Finally, it starts the control application in the background.&lt;br /&gt;
&lt;br /&gt;
== Configuration of automatic start ==&lt;br /&gt;
The content of systemd unit file &amp;lt;code&amp;gt;/lib/systemd/system/aquarium_control.service&amp;lt;/code&amp;gt; as following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
&lt;br /&gt;
Description=Aquarium Control Application&lt;br /&gt;
&lt;br /&gt;
After=multi-user.target&lt;br /&gt;
&lt;br /&gt;
## wait for ntp to get updated time&lt;br /&gt;
After=network-online.target time-sync.target&lt;br /&gt;
Wants=network-online.target time-sync.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
&lt;br /&gt;
Type=forking&lt;br /&gt;
&lt;br /&gt;
ExecStart=bash /usr/local/bin/aquarium_control_startup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upon creation/modification of the unit file, one must run the command &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt; in order to activate the changes.&lt;br /&gt;
&lt;br /&gt;
For starting the control application manually via systemd, one can use the command &amp;lt;code&amp;gt;sudo systemctl start aquarium_control_startup.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Creating message queues for operation or test of aquarium_control ==&lt;br /&gt;
The startup script contains the creation of a set of message queues:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one of the message queues is required for operating the control application. The other message queues are use for parallel SW unit testing.&lt;br /&gt;
&lt;br /&gt;
== Initialize lock file with zero as PID ==&lt;br /&gt;
The startup script contains the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lock file has to be initialised to contain zero upon restart of the server. A missing or empty lock file is interpreted by the control application that something has gone wrong and startup will be aborted. In case of uncontrolled shutdown (e.g. power failure), the PID of the last operation may still be in the lock file, hence a reset to zero is required for this case.&lt;br /&gt;
&lt;br /&gt;
== Start the application to run in the background ==&lt;br /&gt;
The start of the application in the background is triggered with the following command:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=437</id>
		<title>Automatic start by using systemd</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=437"/>
		<updated>2026-02-17T17:49:18Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Configuration of automatic start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Content of the startup script ==&lt;br /&gt;
The shell script for startup of the control application (&amp;lt;code&amp;gt;/usr/local/bin/aquarium_control_startup&amp;lt;/code&amp;gt;) has the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It resets any PID in the lock file from previously instances which were potentially not shut down correctly (for example, in case of power failure).&lt;br /&gt;
It creates the message queue file which is not a file on the hard drive and sets permission accordingly.&lt;br /&gt;
Finally, it starts the control application in the background.&lt;br /&gt;
&lt;br /&gt;
== Configuration of automatic start ==&lt;br /&gt;
The content of systemd unit file &amp;lt;code&amp;gt;/lib/systemd/system/aquarium_control.service&amp;lt;/code&amp;gt; as following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
&lt;br /&gt;
Description=Aquarium Control Application&lt;br /&gt;
&lt;br /&gt;
After=multi-user.target&lt;br /&gt;
&lt;br /&gt;
\# wait for ntp to get updated time&lt;br /&gt;
After=network-online.target time-sync.target&lt;br /&gt;
Wants=network-online.target time-sync.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
&lt;br /&gt;
Type=forking&lt;br /&gt;
&lt;br /&gt;
ExecStart=bash /usr/local/bin/aquarium_control_startup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upon creation/modification of the unit file, one must run the command &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt; in order to activate the changes.&lt;br /&gt;
&lt;br /&gt;
For starting the control application manually via systemd, one can use the command &amp;lt;code&amp;gt;sudo systemctl start aquarium_control_startup.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Creating message queues for operation or test of aquarium_control ==&lt;br /&gt;
The startup script contains the creation of a set of message queues:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one of the message queues is required for operating the control application. The other message queues are use for parallel SW unit testing.&lt;br /&gt;
&lt;br /&gt;
== Initialize lock file with zero as PID ==&lt;br /&gt;
The startup script contains the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lock file has to be initialised to contain zero upon restart of the server. A missing or empty lock file is interpreted by the control application that something has gone wrong and startup will be aborted. In case of uncontrolled shutdown (e.g. power failure), the PID of the last operation may still be in the lock file, hence a reset to zero is required for this case.&lt;br /&gt;
&lt;br /&gt;
== Start the application to run in the background ==&lt;br /&gt;
The start of the application in the background is triggered with the following command:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=436</id>
		<title>Automatic start by using systemd</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Automatic_start_by_using_systemd&amp;diff=436"/>
		<updated>2026-02-17T17:49:00Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Configuration of automatic start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Content of the startup script ==&lt;br /&gt;
The shell script for startup of the control application (&amp;lt;code&amp;gt;/usr/local/bin/aquarium_control_startup&amp;lt;/code&amp;gt;) has the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It resets any PID in the lock file from previously instances which were potentially not shut down correctly (for example, in case of power failure).&lt;br /&gt;
It creates the message queue file which is not a file on the hard drive and sets permission accordingly.&lt;br /&gt;
Finally, it starts the control application in the background.&lt;br /&gt;
&lt;br /&gt;
== Configuration of automatic start ==&lt;br /&gt;
The content of systemd unit file &amp;lt;code&amp;gt;/lib/systemd/system/aquarium_control.service&amp;lt;/code&amp;gt; as following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
&lt;br /&gt;
Description=Aquarium Control Application&lt;br /&gt;
&lt;br /&gt;
After=multi-user.target&lt;br /&gt;
&lt;br /&gt;
# wait for ntp to get updated time&lt;br /&gt;
After=network-online.target time-sync.target&lt;br /&gt;
Wants=network-online.target time-sync.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
&lt;br /&gt;
Type=forking&lt;br /&gt;
&lt;br /&gt;
ExecStart=bash /usr/local/bin/aquarium_control_startup&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upon creation/modification of the unit file, one must run the command &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt; in order to activate the changes.&lt;br /&gt;
&lt;br /&gt;
For starting the control application manually via systemd, one can use the command &amp;lt;code&amp;gt;sudo systemctl start aquarium_control_startup.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Creating message queues for operation or test of aquarium_control ==&lt;br /&gt;
The startup script contains the creation of a set of message queues:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.5UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.4UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.6UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.7UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.8UXp&lt;br /&gt;
&lt;br /&gt;
sudo touch /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&lt;br /&gt;
sudo chmod o+rwx /dev/mqueue/aquarium_control.9UXp&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one of the message queues is required for operating the control application. The other message queues are use for parallel SW unit testing.&lt;br /&gt;
&lt;br /&gt;
== Initialize lock file with zero as PID ==&lt;br /&gt;
The startup script contains the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
sudo echo 0 &amp;gt; /var/local/aquarium-ctrl.pid&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lock file has to be initialised to contain zero upon restart of the server. A missing or empty lock file is interpreted by the control application that something has gone wrong and startup will be aborted. In case of uncontrolled shutdown (e.g. power failure), the PID of the last operation may still be in the lock file, hence a reset to zero is required for this case.&lt;br /&gt;
&lt;br /&gt;
== Start the application to run in the background ==&lt;br /&gt;
The start of the application in the background is triggered with the following command:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/usr/local/bin/aquarium_control &amp;gt; /dev/null&amp;amp;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=435</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=435"/>
		<updated>2026-01-30T18:17:16Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Threads */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
* [[Temperature gradient calculation]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* temperature gradient calculation&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
|-&lt;br /&gt;
| temperature_gradient || [[Temperature gradient calculation]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning software|commissioning of the aquarium control]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=434</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=434"/>
		<updated>2026-01-30T18:16:39Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Threads */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
* [[Temperature gradient calculation]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* temperature gradient calculation&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
|-&lt;br /&gt;
| temperature_gradient || [[Temperature Gradient Calculation]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning software|commissioning of the aquarium control]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=433</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=433"/>
		<updated>2026-01-30T18:15:54Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Phase 5: Component Initialization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
* [[Temperature gradient calculation]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* temperature gradient calculation&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning software|commissioning of the aquarium control]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Temperature_gradient_calculation&amp;diff=432</id>
		<title>Temperature gradient calculation</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Temperature_gradient_calculation&amp;diff=432"/>
		<updated>2026-01-30T18:14:12Z</updated>

		<summary type="html">&lt;p&gt;Uwe: Created page with &amp;quot;= Temperature Gradient Calculation =  The **Temperature Gradient Calculation** module in the Aquarium Control system is responsible for determining the rate of change of the water temperature over time. By calculating the slope (gradient) of the temperature curve, the system can identify trends—such as heating up, cooling down, or stable conditions—more effectively than by looking at instantaneous values alone. This data serves as basis for more sophisticated diagnos...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Temperature Gradient Calculation =&lt;br /&gt;
&lt;br /&gt;
The **Temperature Gradient Calculation** module in the Aquarium Control system is responsible for determining the rate of change of the water temperature over time. By calculating the slope (gradient) of the temperature curve, the system can identify trends—such as heating up, cooling down, or stable conditions—more effectively than by looking at instantaneous values alone. This data serves as basis for more sophisticated diagnostics.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The primary purpose of this module is to provide a reliable trend indicator for the thermal control logic. It helps in:&lt;br /&gt;
* **Verifying Actuator Effectiveness**: Confirming that the heater is actually raising the temperature or that the fans are cooling it down.&lt;br /&gt;
* **Anomaly Detection**: Identifying rapid temperature spikes or drops that might indicate sensor failure or equipment malfunction.&lt;br /&gt;
* **Predictive Control**: Allowing control loops to react to the ''direction'' of the temperature change: Providing the basis for PID-control, potentially reducing overshoot - this feature is currently not planned for implementation.&lt;br /&gt;
&lt;br /&gt;
== Algorithm ==&lt;br /&gt;
&lt;br /&gt;
The module employs a **Least Squares Linear Regression** algorithm on a sliding window of historical data points to calculate the gradient. This method is chosen to smooth out sensor noise and quantization errors.&lt;br /&gt;
&lt;br /&gt;
=== Process ===&lt;br /&gt;
# **Sampling**: The module performs measurement calculation at a configured `sampling_interval`.&lt;br /&gt;
# **Data Acquisition**: It retrieves the current water temperature from the central `SensorManager` and captures the current timestamp.&lt;br /&gt;
# **Storage**: The data point $(t, T)$ is pushed into a First-In-First-Out (FIFO) buffer (sliding window).&lt;br /&gt;
# **Window Management**: If the buffer exceeds the configured `sample_size`, the oldest data point is removed.&lt;br /&gt;
# **Calculation**: Once the buffer is full, the gradient $m$ is calculated using the formula:&lt;br /&gt;
#:&amp;lt;math&amp;gt;m = \frac{N \sum(xy) - \sum x \sum y}{N \sum x^2 - (\sum x)^2}&amp;lt;/math&amp;gt;&lt;br /&gt;
#:Where:&lt;br /&gt;
#:* $N$ is the number of samples.&lt;br /&gt;
#:* $x$ is the time in seconds (normalized relative to the oldest sample to preserve floating-point precision).&lt;br /&gt;
#:* $y$ is the temperature in degrees Celsius.&lt;br /&gt;
# **Output**: The resulting slope $m$ (representing °C/second) is updated in a shared memory location protected by a Mutex.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The behavior of the gradient calculation is defined in the application's TOML configuration file (typically `/etc/aquarium_control/aquarium_control.toml`) under the `[temperature_gradient]` section.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Parameter !! Type !! Description !! Constraints&lt;br /&gt;
|-&lt;br /&gt;
| `active` || Boolean || Master switch to enable or disable the calculation logic. || `true` / `false`&lt;br /&gt;
|-&lt;br /&gt;
| `execute` || Boolean || Determines if the thread should be spawned (primarily for testing). || `true` / `false`&lt;br /&gt;
|-&lt;br /&gt;
| `sampling_interval` || Integer || The time duration (in seconds) between two consecutive temperature samples. || Must be &amp;gt; 0.&lt;br /&gt;
|-&lt;br /&gt;
| `sample_size` || Integer || The number of historical data points to keep in the sliding window for regression. || Must be between 2 and 100.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Example Configuration ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;toml&amp;quot;&amp;gt;&lt;br /&gt;
[temperature_gradient]&lt;br /&gt;
active = true&lt;br /&gt;
execute = true&lt;br /&gt;
sampling_interval = 10   # Take a sample every 10 seconds&lt;br /&gt;
sample_size = 20         # Calculate trend based on the last 20 samples (200 seconds window)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Architecture and Integration ==&lt;br /&gt;
&lt;br /&gt;
The Temperature Gradient module is implemented as a standalone thread that runs concurrently with other system components.&lt;br /&gt;
&lt;br /&gt;
=== Dependencies ===&lt;br /&gt;
* **Input**: It consumes data from the `SensorManager`. Specifically, it reads the `water_temperature` field from the shared `SensorManagerSignals` structure.&lt;br /&gt;
* **Output**: It writes the calculated gradient (`f64`) to a shared `Arc&amp;lt;Mutex&amp;lt;f64&amp;gt;&amp;gt;`, which can be read by other components (e.g., logging or safety checks).&lt;br /&gt;
* **Lifecycle**: It is managed by the `SignalHandler`. It listens for `Quit` or `Terminate` commands via a dedicated channel to ensure graceful shutdown.&lt;br /&gt;
&lt;br /&gt;
=== Thread Communication ===&lt;br /&gt;
The module uses Rust's `mpsc` (multi-producer, single-consumer) channels for control signals and `Arc&amp;lt;Mutex&amp;lt;...&amp;gt;&amp;gt;` for data sharing.&lt;br /&gt;
&lt;br /&gt;
{{Graph:Mermaid|&lt;br /&gt;
graph LR&lt;br /&gt;
    SensorManager[SensorManager] -.-&amp;gt;|Reads Temp| TempGradient[TemperatureGradient]&lt;br /&gt;
    TempGradient --&amp;gt;|Updates Gradient| SharedState[Mutex&amp;lt;f64&amp;gt;]&lt;br /&gt;
    SignalHandler[SignalHandler] --&amp;gt;|Control Signals| TempGradient&lt;br /&gt;
    TempGradient --&amp;gt;|Acknowledge| SignalHandler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Error Handling ==&lt;br /&gt;
&lt;br /&gt;
The module defines specific error types in `TemperatureGradientError` to handle initialization failures:&lt;br /&gt;
* **InvalidSamplingInterval**: Raised if the interval is set to 0.&lt;br /&gt;
* **InvalidSampleSize**: Raised if the sample size is outside the allowed range (2-100).&lt;br /&gt;
&lt;br /&gt;
During runtime, the module includes logic to prevent log flooding. If it fails to acquire a lock on the sensor data or the output mutex, it logs the error once and inhibits further identical error logs until a successful operation occurs.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=431</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=431"/>
		<updated>2026-01-30T18:09:27Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
* [[Temperature gradient calculation]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning software|commissioning of the aquarium control]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=430</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=430"/>
		<updated>2026-01-27T06:43:40Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;This is the Aquarium Control developer documentation.&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control is a control system for salt-water aquariums.&lt;br /&gt;
&lt;br /&gt;
The main features include:&lt;br /&gt;
* [[Refill control for fresh water]]&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity|Data acquisition of temperature, pH, conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity|Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* Temperature control using ventilation fans and heater&lt;br /&gt;
* Automatic feeder&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The components of the control system are assembled in one [[control cabinet]].&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control consists of the following SW elements:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!|Repository name&lt;br /&gt;
!|Description&lt;br /&gt;
!|Programming language&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-android-mobile-app/ AquariumControl Android Mobile App]&lt;br /&gt;
|| [[Android application]]&lt;br /&gt;
|| Kotlin&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-api AquariumControl API]&lt;br /&gt;
|| [[REST API]]&lt;br /&gt;
|| php&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-controllino-relay-actuator AquariumControl Controllino Relay Actuator]&lt;br /&gt;
|| [[Arduino-based relay actuation]]&lt;br /&gt;
|| C&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-database AquariumControl Database]&lt;br /&gt;
|| [[SQL database]] using MariaDB&lt;br /&gt;
|| SQL&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-ios-mobile-app AquariumControl iOS Mobile App]&lt;br /&gt;
|| [https://getapp.cc/app/6480310799 App for Apple mobile devices] &lt;br /&gt;
|| Swift&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-main-control AquariumControl Main Control]&lt;br /&gt;
|| [[Control application]], [[Terminal client]] and test server&lt;br /&gt;
|| Rust&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-webpage AquariumControl Webpage]&lt;br /&gt;
|| [[Dynamic Webpage]] &lt;br /&gt;
|| Java Script&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-deb AquariumControl Debian package]&lt;br /&gt;
|| [[Debian package]] &lt;br /&gt;
|| Bash&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The control application, the REST API, the webpage and the SQL database are designed to run on a [https://www.raspberrypi.org Raspberry Pi].&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=429</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=429"/>
		<updated>2026-01-27T06:43:02Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;This is the Aquarium Control developer documentation.&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control is a control system for salt-water aquariums.&lt;br /&gt;
&lt;br /&gt;
The main features include:&lt;br /&gt;
* [[Refill control for fresh water]]&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity|Data acquisition of temperature, pH, conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity|Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* Temperature control using ventilation fans and heater&lt;br /&gt;
* Automatic feeder&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The components of the control system are assembled in one [[control cabinet]].&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control consists of the following SW elements:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!|Repository name&lt;br /&gt;
!|Description&lt;br /&gt;
!|Programming language&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-android-mobile-app/ AquariumControl Android Mobile App]&lt;br /&gt;
|| [[Android application]]&lt;br /&gt;
|| Kotlin&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-api AquariumControl API]&lt;br /&gt;
|| [[REST API]]&lt;br /&gt;
|| php&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-controllino-relay-actuator AquariumControl Controllino Relay Actuator]&lt;br /&gt;
|| [[Arduino-based relay actuation]]&lt;br /&gt;
|| C&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-database AquariumControl Database]&lt;br /&gt;
|| [[SQL database]] using MariaDB&lt;br /&gt;
|| SQL&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-ios-mobile-app AquariumControl iOS Mobile App]&lt;br /&gt;
|| [https://getapp.cc/app/6480310799 App for Apple mobile devices] &lt;br /&gt;
|| Swift&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-main-control AquariumControl Main Control]&lt;br /&gt;
|| [[Control application]], [[Terminal client] and test server]&lt;br /&gt;
|| Rust&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-webpage AquariumControl Webpage]&lt;br /&gt;
|| [[Dynamic Webpage]] &lt;br /&gt;
|| Java Script&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-deb AquariumControl Debian package]&lt;br /&gt;
|| [[Debian package]] &lt;br /&gt;
|| Bash&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The control application, the REST API, the webpage and the SQL database are designed to run on a [https://www.raspberrypi.org Raspberry Pi].&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=428</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=428"/>
		<updated>2026-01-27T06:42:20Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;This is the Aquarium Control developer documentation.&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control is a control system for salt-water aquariums.&lt;br /&gt;
&lt;br /&gt;
The main features include:&lt;br /&gt;
* [[Refill control for fresh water]]&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity|Data acquisition of temperature, pH, conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity|Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* Temperature control using ventilation fans and heater&lt;br /&gt;
* Automatic feeder&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The components of the control system are assembled in one [[control cabinet]].&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control consists of the following SW elements:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!|Repository name&lt;br /&gt;
!|Description&lt;br /&gt;
!|Programming language&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-android-mobile-app/ AquariumControl Android Mobile App]&lt;br /&gt;
|| [[Android application]]&lt;br /&gt;
|| Kotlin&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-api AquariumControl API]&lt;br /&gt;
|| [[REST API]]&lt;br /&gt;
|| php&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-controllino-relay-actuator AquariumControl Controllino Relay Actuator]&lt;br /&gt;
|| [[Arduino-based relay actuation]]&lt;br /&gt;
|| C&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-database AquariumControl Database]&lt;br /&gt;
|| [[SQL database]] using MariaDB&lt;br /&gt;
|| SQL&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-ios-mobile-app AquariumControl iOS Mobile App]&lt;br /&gt;
|| [https://getapp.cc/app/6480310799 App for Apple mobile devices] &lt;br /&gt;
|| Swift&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-main-control AquariumControl Main Control]&lt;br /&gt;
|| [[Control application]] and [[Terminal client]]&lt;br /&gt;
|| Rust&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-webpage AquariumControl Webpage]&lt;br /&gt;
|| [[Dynamic Webpage]] &lt;br /&gt;
|| Java Script&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-deb AquariumControl Debian package]&lt;br /&gt;
|| [[Debian package]] &lt;br /&gt;
|| Bash&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The control application, the REST API, the webpage and the SQL database are designed to run on a [https://www.raspberrypi.org Raspberry Pi].&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=427</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Main_Page&amp;diff=427"/>
		<updated>2026-01-17T10:49:28Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;This is the Aquarium Control developer documentation.&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control is a control system for salt-water aquariums.&lt;br /&gt;
&lt;br /&gt;
The main features include:&lt;br /&gt;
* [[Refill control for fresh water]]&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity|Data acquisition of temperature, pH, conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity|Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* Temperature control using ventilation fans and heater&lt;br /&gt;
* Automatic feeder&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The components of the control system are assembled in one [[control cabinet]].&lt;br /&gt;
&lt;br /&gt;
Aquarium-Control consists of the following SW elements:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!|Repository name&lt;br /&gt;
!|Description&lt;br /&gt;
!|Programming language&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-android-mobile-app/ AquariumControl Android Mobile App]&lt;br /&gt;
|| [[Android application]]&lt;br /&gt;
|| Kotlin&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-api AquariumControl API]&lt;br /&gt;
|| [[REST API]]&lt;br /&gt;
|| php&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-controllino-relay-actuator AquariumControl Controllino Relay Actuator]&lt;br /&gt;
|| [[Arduino-based relay actuation]]&lt;br /&gt;
|| C&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-database AquariumControl Database]&lt;br /&gt;
|| [[SQL database]] using MariaDB&lt;br /&gt;
|| SQL&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-ios-mobile-app AquariumControl iOS Mobile App]&lt;br /&gt;
|| [https://getapp.cc/app/6480310799 App for Apple mobile devices] &lt;br /&gt;
|| Swift&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-main-control AquariumControl Main Control]&lt;br /&gt;
|| [[Control application]] and [[Terminal client]]&lt;br /&gt;
|| Rust&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-test-server AquariumControl Test Server]&lt;br /&gt;
|| Development tool&lt;br /&gt;
|| Rust&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-webpage AquariumControl Webpage]&lt;br /&gt;
|| [[Dynamic Webpage]] &lt;br /&gt;
|| Java Script&lt;br /&gt;
|-&lt;br /&gt;
|| [https://bitbucket.org/in-dubio/aquariumcontrol-deb AquariumControl Debian package]&lt;br /&gt;
|| [[Debian package]] &lt;br /&gt;
|| Bash&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The control application, the REST API, the webpage and the SQL database are designed to run on a [https://www.raspberrypi.org Raspberry Pi].&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=426</id>
		<title>Commissioning software</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=426"/>
		<updated>2026-01-11T16:38:04Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The commissioning software provides functionality to operate all sensors and actuators without activating the controls.&lt;br /&gt;
[[File:commissioning_software.png|thumb|Snapshot of commissioning software]]&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=425</id>
		<title>Commissioning software</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=425"/>
		<updated>2026-01-11T16:37:18Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The commissioning software provides functionality to operate all sensors and actuators without activating the controls.&lt;br /&gt;
[[File:commissioning_sofware.png|thumb|Snapshot of commissioning software]]&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=File:Commissioning_software.png&amp;diff=424</id>
		<title>File:Commissioning software.png</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=File:Commissioning_software.png&amp;diff=424"/>
		<updated>2026-01-11T16:35:51Z</updated>

		<summary type="html">&lt;p&gt;Uwe: Snapshot of commissioning software&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Snapshot of commissioning software&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=423</id>
		<title>Commissioning software</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Commissioning_software&amp;diff=423"/>
		<updated>2026-01-11T13:35:38Z</updated>

		<summary type="html">&lt;p&gt;Uwe: Created page with &amp;quot;The commissioning software provides functionality to operate all sensors and actuators without activating the controls.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The commissioning software provides functionality to operate all sensors and actuators without activating the controls.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=422</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=422"/>
		<updated>2026-01-11T13:34:36Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Commissioning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning software|commissioning of the aquarium control]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=421</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=421"/>
		<updated>2026-01-11T13:34:16Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Commissioning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [[commissioning of the aquarium control|commissioning software]], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=420</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=420"/>
		<updated>2026-01-11T13:34:02Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Commissioning */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the [commissioning of the aquarium control|commissioning software], there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=419</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=419"/>
		<updated>2026-01-11T13:32:27Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
= Architecture =&lt;br /&gt;
== Startup of the application ==&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
=== Phase 1: Command Line &amp;amp; Configuration ===&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
=== Phase 2: System Setup ===&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
=== Phase 3: Database &amp;amp; Hardware ===&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
=== Phase 4: Communication Channels ===&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
=== Phase 5: Component Initialization ===&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
=== Phase 6: Thread Spawning ===&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
=== Architecture of thread configuration ===&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Measurement using Atlas Scientific circuits =&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
= Monitors =&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;br /&gt;
&lt;br /&gt;
= Commissioning =&lt;br /&gt;
For the commissioning of the aquarium control, there is a separate binary which resides in &amp;lt;code&amp;gt;src/bin/commissioning.rs&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=418</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=418"/>
		<updated>2026-01-10T09:26:32Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide manual override switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for the tank level switch.&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each of 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the sensor processing board of the Raspberry Pi.&lt;br /&gt;
#* Note: The sensor processing board transforms the 12V DC to the 5V DC voltage required by the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide voltage from the output of the Controllino to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall connect one USB port of the Raspberry Pi with the USB port of the Controllino.&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=417</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=417"/>
		<updated>2026-01-09T10:26:49Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide manual override switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for the tank level switch.&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each of 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the sensor processing board of the Raspberry Pi.&lt;br /&gt;
#* Note: The sensor processing board transforms the 12V DC to the 5V DC voltage required by the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall connect one USB port of the Raspberry Pi with the USB port of the Controllino.&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=416</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=416"/>
		<updated>2026-01-09T10:25:17Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for the tank level switch.&lt;br /&gt;
# The control cabinet shall provide a pair of rail mount terminals for each of 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the sensor processing board of the Raspberry Pi.&lt;br /&gt;
#* Note: The sensor processing board transforms the 12V DC to the 5V DC voltage required by the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall connect one USB port of the Raspberry Pi with the USB port of the Controllino.&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=415</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=415"/>
		<updated>2026-01-09T10:22:05Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the sensor processing board of the Raspberry Pi.&lt;br /&gt;
#* Note: The sensor processing board transforms the 12V DC to the 5V DC voltage required by the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall connect one USB port of the Raspberry Pi with the USB port of the Controllino.&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=414</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=414"/>
		<updated>2026-01-09T10:20:57Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the sensor processing board of the Raspberry Pi.&lt;br /&gt;
#* Note: The sensor processing board transforms the 12V DC to the 5V DC voltage required by the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=413</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=413"/>
		<updated>2026-01-09T10:12:59Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the Raspberry Pi.&lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=412</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=412"/>
		<updated>2026-01-09T10:10:36Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for overvoltage protection&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=411</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=411"/>
		<updated>2026-01-09T10:09:57Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays (overvoltage protection relay) for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator for each of the following devices to control terminal of their respective overvoltage protection relay:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage to the input of each of the overvoltage protection relays:&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the overvoltage protection to the respective fuse.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=410</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=410"/>
		<updated>2026-01-09T10:04:43Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V DC devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V DC supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall provide 12V DC voltage from the fuse output of each actuator to the rail mount terminal of each actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to the relay inputs of the relay actuator.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the heater to the power socket of the heater.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of the relay actuator to the fuse of the feeder.&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of the feeder to the rail mount terminal for the feeder.&lt;br /&gt;
# The control cabinet shall provide transient overvoltage protection by means of an additional set of relays for each 230V AC pumps:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the relay output of each of the following devices to their respective fuse:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall provide 230V AC voltage from the fuse of each of the following devices to their respective power socket:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=409</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=409"/>
		<updated>2026-01-09T09:51:43Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the 230V AC power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall provide 230V AC supply voltage to 12V power supply. &lt;br /&gt;
# The control cabinet shall provide 12V supply voltage to the relay actuator (Controllino).&lt;br /&gt;
# The control cabinet shall provide 12V voltage to the relay inputs of the Controllino.&lt;br /&gt;
# The control cabinet shall provide 12V voltage from the relay outputs of the Controllino to the fuse of each actuator.&lt;br /&gt;
#* Note: The ventilation fans share one relay output but have distinct fuses.&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=408</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=408"/>
		<updated>2026-01-09T09:45:25Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation fans).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 12V devices:&lt;br /&gt;
#* all Balling mineral dosing pumps&lt;br /&gt;
#* fresh-water refill pump&lt;br /&gt;
#* ventilation fan #1&lt;br /&gt;
#* ventilation fan #2&lt;br /&gt;
# The control cabinet shall provide a rail mount terminal block for all 230V devices that do not use a power socket:&lt;br /&gt;
#* feeder&lt;br /&gt;
# The control cabinet shall allow to route all cables (power supply, actuators, sensors) to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=407</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=407"/>
		<updated>2026-01-09T09:40:00Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall provide signal indicator lamps for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall allow to route the cables to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=406</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=406"/>
		<updated>2026-01-09T09:32:26Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation).&lt;br /&gt;
# The control cabinet shall provide switches accessible without opening the cabinet allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
# The control cabinet shall allow to route the cables to outside of the cabinet - preferably at the bottom of the cabinet.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=405</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=405"/>
		<updated>2026-01-09T09:28:42Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator (all pumps, skimmer, feeder, heater, ventilation).&lt;br /&gt;
# The control cabinet shall provide switches allowing to switch off the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;br /&gt;
#* Feeder&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=404</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=404"/>
		<updated>2026-01-09T09:20:50Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator.&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
#* Protein skimmer&lt;br /&gt;
#* Main pump #1&lt;br /&gt;
#* Main pump #2&lt;br /&gt;
#* Auxiliary pump #1&lt;br /&gt;
#* Auxiliary pump #2&lt;br /&gt;
#* Heater&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=403</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=403"/>
		<updated>2026-01-09T09:20:33Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator.&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
* Protein skimmer&lt;br /&gt;
* Main pump #1&lt;br /&gt;
* Main pump #2&lt;br /&gt;
* Auxiliary pump #1&lt;br /&gt;
* Auxiliary pump #2&lt;br /&gt;
* Heater&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=402</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=402"/>
		<updated>2026-01-09T09:20:17Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator.&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
** Protein skimmer&lt;br /&gt;
** Main pump #1&lt;br /&gt;
** Main pump #2&lt;br /&gt;
** Auxiliary pump #1&lt;br /&gt;
** Auxiliary pump #2&lt;br /&gt;
** Heater&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=401</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=401"/>
		<updated>2026-01-09T09:19:52Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;br /&gt;
# The control cabinet shall limit the current drawn by each actuator.&lt;br /&gt;
# The control cabinet shall provide power sockets for the following devices:&lt;br /&gt;
## Protein skimmer&lt;br /&gt;
## Main pump #1&lt;br /&gt;
## Main pump #2&lt;br /&gt;
## Auxiliary pump #1&lt;br /&gt;
## Auxiliary pump #2&lt;br /&gt;
## Heater&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=400</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=400"/>
		<updated>2026-01-09T09:17:18Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
# The control cabinet shall have the possibility to cut off the connection to the power supply (all wires).&lt;br /&gt;
&lt;br /&gt;
# The control cabinet shall limit the current drawn from the power supply.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=399</id>
		<title>Control cabinet</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_cabinet&amp;diff=399"/>
		<updated>2026-01-09T08:52:20Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The control cabinet includes the following components&lt;br /&gt;
&lt;br /&gt;
* Main control unit (Raspberry Pi)&lt;br /&gt;
* Relay actuation unit&lt;br /&gt;
* Power supply 12V&lt;br /&gt;
* Fuses&lt;br /&gt;
* Circuit breaker&lt;br /&gt;
* Main switch&lt;br /&gt;
* Relays for [[manual control of pumps and skimmer]]&lt;br /&gt;
* Sockets for power output to pumps and skimmer&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=398</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=398"/>
		<updated>2026-01-08T18:31:57Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Measurement using Atlas Scientific circuits */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Measurement using Atlas Scientific circuits ==&lt;br /&gt;
The core Abstraction (&amp;lt;code&amp;gt;AtlasScientificDriver&amp;lt;/code&amp;gt; Trait) is defined in &amp;lt;code&amp;gt;src/sensors/atlas_scientific_driver.rs&amp;lt;/code&amp;gt;, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
* &amp;lt;code&amp;gt;send_request_to_i2c_interface&amp;lt;/code&amp;gt;: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
* &amp;lt;code&amp;gt;receive_response_from_i2c_interface&amp;lt;/code&amp;gt;: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
* &amp;lt;code&amp;gt;device_init&amp;lt;/code&amp;gt;: Performs hardware-specific setup (crucial for OEM type sensor circuit).&lt;br /&gt;
&lt;br /&gt;
Circuit-type-specific implementations&lt;br /&gt;
* OEM Driver (&amp;lt;code&amp;gt;AtlasScientificOem&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
** Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to &amp;lt;code&amp;gt;REG_WAKEUP&amp;lt;/code&amp;gt;) and verifies the hardware by reading the &amp;lt;code&amp;gt;REG_DEVICE_TYPE&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Read Cycle: Writes a register address (e.g., &amp;lt;code&amp;gt;REG_DATA_MSB_PH&amp;lt;/code&amp;gt;), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
** Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
* EZO Driver (&amp;lt;code&amp;gt;AtlasScientificEzo&amp;lt;/code&amp;gt;):&lt;br /&gt;
** Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
** Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
** Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
** Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
Context and factory (&amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct)&lt;br /&gt;
* The main &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; struct acts as the context. It holds a &amp;lt;code&amp;gt;HashMap&amp;lt;AquariumSignal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Factory Logic: The &amp;lt;code&amp;gt;create_drivers&amp;lt;/code&amp;gt; method functions as a factory. It reads the &amp;lt;code&amp;gt;aquarium_control.toml&amp;lt;/code&amp;gt; configuration (specifically fields like &amp;lt;code&amp;gt;sensor_type_ph = &amp;quot;oem&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;ezo&amp;quot;&amp;lt;/code&amp;gt;) and&lt;br /&gt;
instantiates the correct driver implementation for each sensor (temperature, pH, conductivity).&lt;br /&gt;
* Execution: The main thread loop calls &amp;lt;code&amp;gt;driver.send_request...&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;driver.receive_response...&amp;lt;/code&amp;gt; on the active driver, unaware of whether it is communicating via binary registers or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
Communication Flow&lt;br /&gt;
&lt;br /&gt;
The architecture decouples protocol logic from bus I/O:&lt;br /&gt;
# Driver creates an abstraction-specific &amp;lt;code&amp;gt;I2cRequest&amp;lt;/code&amp;gt; (containing address, write buffer, read length, delay).&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread sends this request via a channel to the &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread.&lt;br /&gt;
# &amp;lt;code&amp;gt;I2cInterface&amp;lt;/code&amp;gt; thread performs the physical I2C transaction.&lt;br /&gt;
# &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; thread receives the raw bytes and passes them back to the driver for parsing.&lt;br /&gt;
# Additionally, &amp;lt;code&amp;gt;AtlasScientific&amp;lt;/code&amp;gt; performs measurement value checks informing deviations to &amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
This design enables the system to mix and match sensor types (e.g., an OEM type pH sensor circuit with an EZO type temperature sensor circuit) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
== Monitors ==&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=397</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=397"/>
		<updated>2026-01-08T18:21:21Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Architecture */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Measurement using Atlas Scientific circuits ==&lt;br /&gt;
1. Core Abstraction (`AtlasScientificDriver` Trait)&lt;br /&gt;
      Defined in src/sensors/atlas_scientific_driver.rs, this trait serves as the common interface for all sensor types. It enforces three key behaviors:&lt;br /&gt;
       * send_request_to_i2c_interface: Encapsulates how to trigger a measurement (e.g., constructing specific I2C commands).&lt;br /&gt;
       * receive_response_from_i2c_interface: Handles parsing the raw byte response from the I2C bus into a normalized floating-point value.&lt;br /&gt;
       * device_init: Performs hardware-specific setup (crucial for OEM sensors).&lt;br /&gt;
&lt;br /&gt;
   2. Specific Implementations (The Strategies)&lt;br /&gt;
&lt;br /&gt;
       * OEM Driver (`AtlasScientificOem`):&lt;br /&gt;
           * Protocol: Uses a binary, register-based protocol.&lt;br /&gt;
           * Initialization: Requires an explicit &amp;quot;Wake Up&amp;quot; command (writing to REG_WAKEUP) and verifies the hardware by reading the REG_DEVICE_TYPE.&lt;br /&gt;
           * Read Cycle: Writes a register address (e.g., REG_DATA_MSB_PH), waits for a short processing time, and reads 4 bytes.&lt;br /&gt;
           * Parsing: Decodes the 4-byte response as a Big Endian unsigned integer and divides it by a specific scale factor (e.g., 1000.0) to get the float value.&lt;br /&gt;
&lt;br /&gt;
       * EZO Driver (`AtlasScientificEzo`):&lt;br /&gt;
           * Protocol: Uses a text-based (ASCII) command protocol.&lt;br /&gt;
           * Initialization: Minimal or no-op (these devices are typically always ready or auto-on).&lt;br /&gt;
           * Read Cycle: Sends the ASCII character 'R', waits for a longer processing time, and reads a fixed 8-byte response.&lt;br /&gt;
           * Parsing: Validates &amp;quot;magic&amp;quot; start/end bytes (1 and 0), converts the inner ASCII string (e.g., &amp;quot;23.50&amp;quot;) to a float.&lt;br /&gt;
&lt;br /&gt;
   3. Context &amp;amp; Factory (`AtlasScientific` Struct)&lt;br /&gt;
       * The main AtlasScientific struct acts as the &amp;quot;Context&amp;quot;. It holds a HashMap&amp;lt;AquariumSignal, Box&amp;lt;dyn AtlasScientificDriver&amp;gt;&amp;gt;.&lt;br /&gt;
       * Factory Logic: The create_drivers method functions as a factory. It reads the aquarium_control.toml configuration (specifically fields like sensor_type_ph = &amp;quot;oem&amp;quot; or &amp;quot;ezo&amp;quot;) and&lt;br /&gt;
         instantiates the correct driver implementation for each sensor (Temperature, pH, Conductivity).&lt;br /&gt;
       * Execution: The main thread loop simply calls driver.send_request... and driver.receive_response... on the active driver, unaware of whether it is communicating via binary registers&lt;br /&gt;
         or ASCII commands.&lt;br /&gt;
&lt;br /&gt;
  Communication Flow&lt;br /&gt;
&lt;br /&gt;
  The architecture completely decouples protocol logic from bus I/O:&lt;br /&gt;
   1. Driver creates an abstraction-specific I2cRequest (containing address, write buffer, read length, delay).&lt;br /&gt;
   2. AtlasScientific Thread sends this request via a channel to the I2cInterface Thread.&lt;br /&gt;
   3. I2cInterface Thread performs the physical I2C transaction.&lt;br /&gt;
   4. AtlasScientific Thread receives the raw bytes and passes them back to the Driver for parsing.&lt;br /&gt;
&lt;br /&gt;
  This design enables the system to mix and match sensor types (e.g., an OEM pH sensor with an EZO temperature sensor) purely through configuration changes.&lt;br /&gt;
&lt;br /&gt;
== Monitors ==&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=396</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=396"/>
		<updated>2026-01-08T10:56:11Z</updated>

		<summary type="html">&lt;p&gt;Uwe: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Monitors ==&lt;br /&gt;
The Monitors module (&amp;lt;code&amp;gt;src/watchmen/monitors.rs&amp;lt;/code&amp;gt;) is a dedicated thread that aggregates and stores historical system state information.&lt;br /&gt;
It interacts with the following modules:&lt;br /&gt;
* Refill&lt;br /&gt;
* Signal handler&lt;br /&gt;
&lt;br /&gt;
The Monitors thread receives data from the other thread by polling the channels.&lt;br /&gt;
&lt;br /&gt;
The data is transferred in specific structs (&amp;quot;Views&amp;quot;), e.g. &amp;lt;code&amp;gt;RefillView&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Monitors&amp;lt;/code&amp;gt; contains a deduplication logic: Data is only stored when it differs from previous sample.&lt;br /&gt;
&lt;br /&gt;
The number of samples is also limited (rolling window), to avoid overflow.&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=395</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=395"/>
		<updated>2026-01-08T10:05:14Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Phase 5: Component Initialization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
Instantiates all high-level control components:&lt;br /&gt;
* data logger&lt;br /&gt;
* sensor manager&lt;br /&gt;
* relay manager&lt;br /&gt;
* food injection&lt;br /&gt;
* mineral dosing (balling)&lt;br /&gt;
* water injection/refill&lt;br /&gt;
* heating control&lt;br /&gt;
* ventilation control&lt;br /&gt;
* monitors&lt;br /&gt;
* watchdog&lt;br /&gt;
* schedule checker&lt;br /&gt;
* IPC messaging system&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=394</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=394"/>
		<updated>2026-01-08T10:04:58Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Phase 5: Component Initialization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
* Instantiates all high-level control components:&lt;br /&gt;
** data logger&lt;br /&gt;
** sensor manager&lt;br /&gt;
** relay manager&lt;br /&gt;
** food injection&lt;br /&gt;
** mineral dosing (balling)&lt;br /&gt;
** water injection/refill&lt;br /&gt;
** heating control&lt;br /&gt;
** ventilation control&lt;br /&gt;
** monitors&lt;br /&gt;
** watchdog&lt;br /&gt;
** schedule checker&lt;br /&gt;
** IPC messaging system&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=393</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=393"/>
		<updated>2026-01-08T10:03:28Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Phase 3: Database &amp;amp; Hardware */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
** RGB LEDs&lt;br /&gt;
** GPIO handlers&lt;br /&gt;
** Tank level switch&lt;br /&gt;
** I2C interface&lt;br /&gt;
** Atlas Scientific sensors&lt;br /&gt;
** DHT temperature/humidity sensors&lt;br /&gt;
** Relay actuator (Controllino)&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
* Instantiates all system components:&lt;br /&gt;
    - Data loggers, sensor managers, relay managers&lt;br /&gt;
    - Food injection, mineral dosing (balling), water injection/refill&lt;br /&gt;
    - Heating/ventilation control&lt;br /&gt;
    - Monitors, watchdog, schedule checker&lt;br /&gt;
    - IPC messaging system (Linux)&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=392</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=392"/>
		<updated>2026-01-08T10:01:54Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Architecture */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Sets the default config file: &amp;lt;code&amp;gt;/etc/aquarium_control/aquarium_control.toml&amp;lt;/code&amp;gt;&lt;br /&gt;
* Loads configuration and creates &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
* Initializes the logging system&lt;br /&gt;
* Logs version information and executable hash&lt;br /&gt;
* Verifies root privileges (required for hardware access)&lt;br /&gt;
* Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Database &amp;amp; Hardware ====&lt;br /&gt;
* Connects to database (MariaDB)&lt;br /&gt;
* Creates component-specific SQL interfaces (&amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Balling&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Refill&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Heating&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Feed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Data&amp;lt;/code&amp;gt;)&lt;br /&gt;
* Validates database schema and version compatibility&lt;br /&gt;
* Initializes hardware components if configured:&lt;br /&gt;
    - RGB LEDs, GPIO handlers&lt;br /&gt;
    - Tank level switches&lt;br /&gt;
    - I2C interfaces&lt;br /&gt;
    - Atlas Scientific sensors&lt;br /&gt;
    - DHT temperature/humidity sensors&lt;br /&gt;
&lt;br /&gt;
==== Phase 4: Communication Channels ====&lt;br /&gt;
* Creates the &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; struct containing ~30+ inter-thread communication channels&lt;br /&gt;
* Uses custom &amp;lt;code&amp;gt;AquaSender&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;AquaReceiver&amp;lt;/code&amp;gt; wrappers for MPSC channels&lt;br /&gt;
* Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
==== Phase 5: Component Initialization ====&lt;br /&gt;
* Instantiates all system components:&lt;br /&gt;
    - Data loggers, sensor managers, relay managers&lt;br /&gt;
    - Food injection, mineral dosing (balling), water injection/refill&lt;br /&gt;
    - Heating/ventilation control&lt;br /&gt;
    - Monitors, watchdog, schedule checker&lt;br /&gt;
    - IPC messaging system (Linux)&lt;br /&gt;
&lt;br /&gt;
==== Phase 6: Thread Spawning ====&lt;br /&gt;
* Uses &amp;lt;code&amp;gt;std::thread::scope&amp;lt;/code&amp;gt; for guaranteed cleanup&lt;br /&gt;
* Spawns threads conditionally based on &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; flags&lt;br /&gt;
* Critical: A 3-second startup delay allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
==== Architecture of thread configuration ====&lt;br /&gt;
* The &amp;lt;code&amp;gt;Channels&amp;lt;/code&amp;gt; module (&amp;lt;code&amp;gt;src/launch/channels.rs&amp;lt;/code&amp;gt;) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator.&lt;br /&gt;
* The &amp;lt;code&amp;gt;ExecutionConfig&amp;lt;/code&amp;gt; decouples configuration from execution - threads only receive flags about which modules are active, not the full config - this also avoids ownership issues.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
	<entry>
		<id>http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=391</id>
		<title>Control application</title>
		<link rel="alternate" type="text/html" href="http://217.79.180.177/mediawiki/index.php?title=Control_application&amp;diff=391"/>
		<updated>2026-01-08T09:55:30Z</updated>

		<summary type="html">&lt;p&gt;Uwe: /* Startup of the application */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The main control application of Aquarium control implements the following features:&lt;br /&gt;
&lt;br /&gt;
* [[Data acquisition of water temperature, pH and conductivity]]&lt;br /&gt;
* [[Data acquisition of ambient temperature and humidity]]&lt;br /&gt;
* [[Fresh water refill control|Refill control for fresh water]]&lt;br /&gt;
* Feed control&lt;br /&gt;
* Water temperature control using air ventilation and heater&lt;br /&gt;
* Balling mineral dosing&lt;br /&gt;
&lt;br /&gt;
The control of the relays for operating the devices can use two different modes:&lt;br /&gt;
* [[Arduino-based relay actuation|Using an Arduino-based relay actuation]]&lt;br /&gt;
* Using the GPIO of the Raspberry Pi (requires additional hardware) &lt;br /&gt;
&lt;br /&gt;
Additionally, the main control application implements the following supporting features:&lt;br /&gt;
* [[Version comparison between database and application]] &lt;br /&gt;
* Configuration using a Rust .toml configuration file&lt;br /&gt;
* Logging&lt;br /&gt;
* Command interface to receive instructions from outside of the application via a POSIX message queue&lt;br /&gt;
* Storage of recorded data in SQL database&lt;br /&gt;
* File-based communication to RAM-disk&lt;br /&gt;
* Usage of simulator to run with simulated sensor data for development purposes&lt;br /&gt;
* Schedule checks to limit the hour of day of operating certain actuators&lt;br /&gt;
* [[Communication with HW Watchdog]]&lt;br /&gt;
The application is written in Rust and is [[automatic start by using systemd| automatically started using systemd]].&lt;br /&gt;
&lt;br /&gt;
The documentation of the software is available [http://vps2483992.servdiscount-customer.com/aquarium_control_doc/aquarium_control/ here].&lt;br /&gt;
&lt;br /&gt;
Development for the main control application requires the [[setup of the development environment]].&lt;br /&gt;
&lt;br /&gt;
There is a [[Release procedure|release procedure]] which is highly recommended to be followed also by anyone developing the SW further.&lt;br /&gt;
&lt;br /&gt;
== Architecture ==&lt;br /&gt;
=== Startup of the application ===&lt;br /&gt;
The startup uses a two-layer approach:&lt;br /&gt;
# main() - Simple error handler wrapper that calls run() and exits with code 1 on errors&lt;br /&gt;
# run() - The actual initialization orchestrator that performs the major steps&lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Command Line &amp;amp; Configuration ====&lt;br /&gt;
* Parses command line arguments (&amp;quot;help&amp;quot;, &amp;quot;version&amp;quot;, config file)&lt;br /&gt;
* Default config: /etc/aquarium_control/aquarium_control.toml&lt;br /&gt;
* Loads configuration and creates ExecutionConfig (boolean flags determining which modules to run)&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: System Setup ====&lt;br /&gt;
  - Initializes logging system&lt;br /&gt;
  - Logs version information and executable hash&lt;br /&gt;
  - Verifies root/administrator privileges (required for hardware access)&lt;br /&gt;
  - Publishes process ID to file for client communication&lt;br /&gt;
&lt;br /&gt;
  Phase 3: Database &amp;amp; Hardware&lt;br /&gt;
  - Connects to MySQL database&lt;br /&gt;
  - Creates component-specific SQL interfaces (Schedule, Balling, Refill, Heating, Feed, Data)&lt;br /&gt;
  - Validates database schema and version compatibility&lt;br /&gt;
  - Initializes hardware components if configured:&lt;br /&gt;
    - RGB LEDs, GPIO handlers&lt;br /&gt;
    - Tank level switches&lt;br /&gt;
    - I2C interfaces&lt;br /&gt;
    - Atlas Scientific sensors&lt;br /&gt;
    - DHT temperature/humidity sensors&lt;br /&gt;
&lt;br /&gt;
  Phase 4: Communication Channels&lt;br /&gt;
  - Creates the Channels struct containing ~30+ inter-thread communication channels&lt;br /&gt;
  - Uses custom AquaSender/AquaReceiver wrappers for MPSC channels&lt;br /&gt;
  - Establishes bidirectional and unidirectional message paths between all modules&lt;br /&gt;
&lt;br /&gt;
  Phase 5: Component Initialization&lt;br /&gt;
  - Instantiates all system components:&lt;br /&gt;
    - Data loggers, sensor managers, relay managers&lt;br /&gt;
    - Food injection, mineral dosing (balling), water injection/refill&lt;br /&gt;
    - Heating/ventilation control&lt;br /&gt;
    - Monitors, watchdog, schedule checker&lt;br /&gt;
    - IPC messaging system (Linux)&lt;br /&gt;
&lt;br /&gt;
  Phase 6: Thread Spawning&lt;br /&gt;
  - Uses std::thread::scope for guaranteed cleanup&lt;br /&gt;
  - Spawns threads conditionally based on ExecutionConfig flags&lt;br /&gt;
  - Critical: 3-second startup delay (lines 1082-1089) allows sensors to acquire first data before control loops activate&lt;br /&gt;
&lt;br /&gt;
  Key Architecture&lt;br /&gt;
&lt;br /&gt;
  The Channels module (src/launch/channels.rs) acts as a central wiring diagram, with the Signal Handler serving as the main event coordinator. The application includes a detailed Mermaid diagram (lines 323-403) showing all inter-thread relationships.&lt;br /&gt;
&lt;br /&gt;
  The ExecutionConfig decouples configuration from execution - threads only receive flags about which modules are active, not the full config.&lt;br /&gt;
&lt;br /&gt;
  All components then enter their main execution loops, communicating through the established channel network.&lt;br /&gt;
&lt;br /&gt;
=== Threads ===&lt;br /&gt;
The application spawns the following threads:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|+ Overview of threads&lt;br /&gt;
|-&lt;br /&gt;
! Thread name !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| signal_handler || Receiving signals from the operating system&lt;br /&gt;
|-&lt;br /&gt;
| schedule_check || Polling the database to capture changes of the actuator channel. Informing other threads about it.&lt;br /&gt;
|-&lt;br /&gt;
| sensor_manager || Data acquisition&lt;br /&gt;
|-&lt;br /&gt;
| relay_manager || Actuation of relays&lt;br /&gt;
|-&lt;br /&gt;
| data_logger || Recording of data&lt;br /&gt;
|-&lt;br /&gt;
| tank_level_switch || Postprocessing of tank level switch position signal&lt;br /&gt;
|-&lt;br /&gt;
| refill || Fresh water refill control&lt;br /&gt;
|-&lt;br /&gt;
| heating || Heating control&lt;br /&gt;
|-&lt;br /&gt;
| ventilation || Ventilation control&lt;br /&gt;
|-&lt;br /&gt;
| balling || Balling mineral dosing control&lt;br /&gt;
|-&lt;br /&gt;
| watchdog || Sending alive signal to Raspberry Pi hardware watchdog&lt;br /&gt;
|-&lt;br /&gt;
| monitors || Diagnostics (not implemented as of January, 2026)&lt;br /&gt;
|-&lt;br /&gt;
| messaging || Receiving communication via message queue&lt;br /&gt;
|-&lt;br /&gt;
| memory || Monitoring memory utilization&lt;br /&gt;
|-&lt;br /&gt;
| ds18b20 || Recording data from DS18B20 temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| feed || Feed control&lt;br /&gt;
|-&lt;br /&gt;
| i2c_interface || Communication via I2C&lt;br /&gt;
|-&lt;br /&gt;
| atlas_scientific || Recording data from Atlas Scientific temperature sensor&lt;br /&gt;
|-&lt;br /&gt;
| dht || Recording data from DHT sensor&lt;br /&gt;
|-&lt;br /&gt;
| publish_pid || Writing PID to lock file&lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Uwe</name></author>
	</entry>
</feed>