Skip to content

Commit 057388d

Browse files
authored
Merge pull request #642 from czbiohub-sf/develop
v0.8.0
2 parents d6bd84e + 89cdd82 commit 057388d

File tree

24 files changed

+6539
-127
lines changed

24 files changed

+6539
-127
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2525
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2626
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2727
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

OS_instructions/RTC/RTC_setup.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# RTC
2+
3+
The RTC ensures the Pi has accurate datetime regardless of Internet connection and power loss. To stay up to date, the RTC also needs to be updated whenever the Pi has correct time via network time protocol (NTP) syncing.
4+
5+
The instructions below configure the OS for the following behavior:
6+
- If Pi is disconnected from internet at startup: Update system time from RTC
7+
- If Pi successfully syncs to NTP via internet: Update RTC from system (NTP) time
8+
9+
## Setup instructions
10+
11+
The following files need to live in the Pi's `/etc/` directory:
12+
- `rc.local` sets behavior on boot
13+
- `dhcpcd.exit-hook` sets behavior on Internet connection
14+
15+
Ensure both files have executable permission:
16+
```
17+
sudo chmod +x rc.local
18+
sudo chmod +x dhcpcd.exit-hook
19+
```
20+
21+
## Tests (optional)
22+
23+
Reboot after adding the above files to start the RTC before testing.
24+
25+
### RTC in use
26+
27+
Verify system vs RTC time using `timedatectl` in terminal. You will see a printout like this:
28+
```
29+
Local time: Mon 2025-08-25 15:42:07 PDT
30+
Universal time: Mon 2025-08-25 22:42:07 UTC
31+
RTC time: Mon 2025-08-25 22:42:08
32+
Time zone: America/Los_Angeles (PDT, -0700)
33+
System clock synchronized: yes
34+
NTP service: active
35+
RTC in local TZ: no
36+
```
37+
38+
If the RTC did not successfully start, RTC time will be listed as `n/a`.
39+
40+
### System updated by RTC
41+
42+
Test the use case where there's no Internet connection:
43+
44+
First, turn off NTP sync, otherwise the time will automatically be corrected when `timedatectl` is run.
45+
```
46+
timedatectl set-ntp false
47+
```
48+
49+
Then, manually write an incorrect date/time to the RTC.
50+
```
51+
sudo hwclock --set --date "01/01/2001 00:00:00"
52+
```
53+
54+
Run `timedatectl` to verify the RTC's datetime.
55+
56+
57+
Turn wifi off and reboot. The system time should now be the incorrect RTC time. Be patient as it can take up to 1 min for the system time to update after reconnection.
58+
59+
_NOTE: If you ever want to overwrite system time using the RTC on the spot, run `sudo hwclock -s`._
60+
61+
### RTC updated bt system (NTP) time
62+
63+
Test the use case where the Pi reconnects to Internet:
64+
65+
Turn on wifi when it was previously off or reboot Pi. Both the system time and RTC time should be correct and can be verified by running `timedatectl`
66+
67+
_NOTE: If you ever want to overwrite the RTC using the NTP time on the spot, run `sudo hwclock -w`._
68+
69+
70+
## Supplementary info
71+
- [hwclock](https://linux.die.net/man/8/hwclock) tool
72+
- [timedatectl](https://www.freedesktop.org/software/systemd/man/latest/timedatectl.html) tool
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
# Runs after dhcpcd processes a DHCP event.
3+
# Env vars available: $interface, $reason, $new_ip_address, $new_routers, etc.
4+
5+
# Only act on Wi-Fi and only when we (re)obtained a lease
6+
if [ "$interface" = "wlan0" ]; then
7+
case "$reason" in
8+
BOUND|RENEW|REBIND|REBOOT)
9+
timedatectl set-ntp true
10+
sleep(1)
11+
if timedatectl show -p NTPSynchronized | grep -q "yes"; then
12+
sudo hwclock --systohc --noadjfile --localtime
13+
fi
14+
esac
15+
fi

OS_instructions/RTC/rc.local

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/sh -e
2+
#
3+
# rc.local
4+
#
5+
# This script is executed at the end of each multiuser runlevel.
6+
# Make sure that the script will "exit 0" on success or any other
7+
# value on error.
8+
#
9+
# In order to enable or disable this script just change the execution
10+
# bits.
11+
#
12+
# By default this script does nothing.
13+
14+
# Print the IP address
15+
_IP=$(hostname -I) || true
16+
if [ "$_IP" ]; then
17+
printf "My IP address is %s\n" "$_IP"
18+
fi
19+
20+
# Configure RTC
21+
sudo bash -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device'
22+
23+
# Check if system time is NPT synced
24+
timedatectl set-ntp true
25+
sleep(1)
26+
if timedatectl show -p NTPSynchronized | grep -q "yes"; then
27+
# Update RTC from system time
28+
sudo hwclock --systohc --noadjfile --localtime
29+
fi
30+
31+
# Always update system time from RTC!
32+
# For some reason this doesn't work in else statement
33+
timedatectl set-ntp false
34+
sudo hwclock -s
35+
36+
exit 0

OS_instructions/setup_promtail.sh

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ cat << 'EOF' > "$CONFIG_FILE"
5454
server:
5555
disable: true # Disables Promtail's internal HTTP server
5656
positions:
57-
filename: /home/pi/Documents/ulc-malaria-scope/log_config/positions.yaml # Stores file tracking state
57+
filename: /media/pi/SamsungSSD/positions.yaml # Stores file tracking state
5858
sync_period: 10s
5959
clients:
6060
- url: https://api-grafana.sf.czbiohub.org/loki/push
@@ -71,14 +71,14 @@ scrape_configs:
7171
host: ${HOSTNAME}
7272
__path__: /media/pi/SamsungSSD/logs/*.log # Watches all logs in this directory
7373
pipeline_stages:
74-
- labeldrop:
75-
- filename
7674
- match:
7775
selector: '{app="Remoscope"}'
7876
stages:
7977
- multiline:
8078
firstline: '^\\d{4}-\\d{2}-\\d{2}-\\d{6} .*'
81-
max_wait_time: 5s
79+
max_wait_time: 20s
80+
- labeldrop:
81+
- filename
8282
- regex:
8383
expression: '^\\d{4}-\\d{2}-\\d{2}-\\d{6} - (?P<severity>\\w+) - .*'
8484
- labels:
@@ -98,25 +98,52 @@ echo "Making promtail executable and moving it to /usr/local/bin..."
9898
chmod +x /tmp/promtail-linux-arm
9999
sudo mv /tmp/promtail-linux-arm /usr/local/bin/promtail
100100

101-
# --- Step 4: Create systemd service for Promtail using sed for environment variable substitution ---
102-
echo "Creating systemd service file for promtail..."
101+
echo "Creating Promtail systemd unit…"
102+
103+
# --- STEP 4: wrapper that exits (and lets systemd retry) --------------------
104+
WRAPPER="/usr/local/bin/promtail-retry.sh"
105+
echo "Creating wrapper script at $WRAPPER"
106+
107+
sudo tee "$WRAPPER" > /dev/null <<'EOF'
108+
#!/bin/bash
109+
SSD_DIR="/media/pi/SamsungSSD"
110+
111+
# If the drive isn't mounted yet - retry
112+
if ! mountpoint -q "$SSD_DIR"; then
113+
echo "Promtail: $SSD_DIR not mounted yet, exiting so systemd can retry…" >&2
114+
exit 1
115+
fi
116+
117+
exec /usr/local/bin/promtail \
118+
--config.file=/home/pi/Documents/ulc-malaria-scope/log_config/promtail-config.yaml \
119+
--config.expand-env=true
120+
EOF
121+
122+
sudo chmod +x "$WRAPPER"
123+
124+
# --- STEP 5: promtail-service file setup --------------------
125+
103126
sudo tee /etc/systemd/system/promtail.service > /dev/null <<'EOF'
104127
[Unit]
105-
Description=Promtail Service
106-
After=network.target
128+
Description=Promtail (logs on removable SSD)
129+
After=network-online.target
107130
108131
[Service]
109132
Type=simple
110-
ExecStart=/usr/local/bin/promtail --config.file=/home/pi/Documents/ulc-malaria-scope/log_config/promtail-config.yaml --config.expand-env=true
111-
Restart=on-failure
133+
ExecStart=/usr/local/bin/promtail-retry.sh
134+
Restart=always
135+
RestartSec=10
112136
User=pi
113137
Environment="HOSTNAME=HOST_PLACEHOLDER"
114138
Environment="LOKI_PASSWORD=PASSWORD_PLACEHOLDER"
139+
KillMode=mixed
140+
ExecStopPost=/bin/sync
115141
116142
[Install]
117143
WantedBy=multi-user.target
118144
EOF
119145

146+
120147
echo "Updating systemd service file with provided HOST and PASSWORD..."
121148
sudo sed -i "s/Environment=\"HOSTNAME=HOST_PLACEHOLDER\"/Environment=\"HOSTNAME=${HOST}\"/" /etc/systemd/system/promtail.service
122149
sudo sed -i "s/Environment=\"LOKI_PASSWORD=PASSWORD_PLACEHOLDER\"/Environment=\"LOKI_PASSWORD=${PASSWORD}\"/" /etc/systemd/system/promtail.service
@@ -137,6 +164,24 @@ sudo systemctl daemon-reload
137164
echo "Enabling promtail service..."
138165
sudo systemctl enable promtail.service
139166
echo "Starting promtail service..."
167+
168+
# --- STEP 6: Install udev rule for hard-pull safety --------------------------
169+
echo "Adding udev rule to stop promtail on drive removal…"
170+
171+
sudo tee /etc/udev/rules.d/99-promtail-ssd.rules > /dev/null <<'EOF'
172+
ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_LABEL}=="SamsungSSD", \
173+
RUN+="/usr/bin/systemctl stop promtail.service"
174+
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_LABEL}=="SamsungSSD", \
175+
RUN+="/usr/bin/systemctl start promtail.service"
176+
EOF
177+
sudo udevadm control --reload
178+
179+
# Reload udev so the new rule is active immediately
180+
sudo udevadm control --reload
181+
sudo udevadm trigger --subsystem-match=block # optional: re-evaluate current devices
182+
183+
echo "udev rule installed - Promtail will shut down if the SSD is hard-pulled."
184+
140185
sudo systemctl start promtail.service
141186

142-
echo "Promtail setup complete."
187+
echo "Promtail setup complete."

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def readme():
6565
"remo-dev=ulc_mm_package.QtGUI.dev_run:main",
6666
"remo-fix-focus=ulc_mm_package.utilities.coarse_focus_utility:main",
6767
"remo-pneumatic-calibration=ulc_mm_package.utilities.pneumatic_utility:main",
68+
"remo-zstack=ulc_mm_package.utilities.zstack_utility:main",
6869
]
6970
},
7071
)

0 commit comments

Comments
 (0)