frugal-iot-server 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALLATION.md +380 -123
- package/README.md +6 -6
- package/config.d/logger.yaml +16 -0
- package/config.d/schema/modules.yaml +66 -1
- package/config.d/schema/topics.yaml +184 -2
- package/config.d/server.yaml +28 -4
- package/extras/mosquitto.conf +13 -1
- package/frugal-iot-server.js +71 -5
- package/lib/api-routes.js +3 -0
- package/lib/data-loader.js +11 -4
- package/lib/housekeeping.js +251 -0
- package/lib/logger-client.js +16 -0
- package/package.json +10 -5
- package/public/service-worker.js +1 -1
- package/scripts/addorganization.zsh +59 -15
- package/scripts/check-schema.js +127 -0
- package/scripts/copy-schema-to-examples.zsh +55 -0
- package/scripts/diagnostic.zsh +382 -0
- package/scripts/init.zsh +37 -10
- package/scripts/prerelease.zsh +125 -0
- package/scripts/setpassword.zsh +3 -3
package/INSTALLATION.md
CHANGED
|
@@ -5,33 +5,61 @@ an MQTT broker (Mosquitto), the Frugal IoT server, the logger that writes sensor
|
|
|
5
5
|
and the web UI. Once installed, the Pi works **offline** — your sensor nodes talk to the Pi,
|
|
6
6
|
and you view the data from a phone or laptop on the same Wi-Fi. No internet needed after setup.
|
|
7
7
|
|
|
8
|
-
Two hardware paths are covered:
|
|
9
|
-
|
|
10
|
-
* [Raspberry Pi 4](#part-a--raspberry-pi-4) — the recommended, tested path.
|
|
11
|
-
* [Raspberry Pi Zero W](#part-b--raspberry-pi-zero-w) — smaller and cheaper, **not yet tested**, see the open questions in that section.
|
|
12
|
-
|
|
13
8
|
If you already have a working Linux server (not a Pi), you do not need this document —
|
|
14
9
|
see [README.md](https://github.com/mitra42/frugal-iot-server/blob/main/README.md) instead.
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
**Read the steps in order.** Anything specific to one board is marked in the step it belongs to,
|
|
12
|
+
like this:
|
|
13
|
+
|
|
14
|
+
> **Pi Zero W:** extra detail that only applies to a Zero W. Skip these on a Pi 4.
|
|
15
|
+
|
|
16
|
+
> **Status:** followed on hardware — a Raspberry Pi 4 through step 9, and a Pi Zero W through step 8
|
|
17
|
+
> (see [Tested on](#tested-on)) — and corrected from what those runs found. HTTPS/OTA in step 10 is
|
|
18
|
+
> not written yet. Remaining uncertainties are under [Open questions](#open-questions) — please add
|
|
19
|
+
> your findings there as you go.
|
|
20
|
+
|
|
21
|
+
**Already have a Frugal IoT server running and just want a newer version?** Skip everything below
|
|
22
|
+
and go to [Upgrading](#upgrading).
|
|
23
|
+
|
|
24
|
+
**If a step does not do what it says here**, once you reach step 4 you can run
|
|
25
|
+
`npx --no frugal-iot-diagnostic` from your install directory — it inspects the whole installation and
|
|
26
|
+
reports what looks wrong. See [When something does not work](#when-something-does-not-work).
|
|
19
27
|
|
|
20
28
|
---
|
|
21
29
|
|
|
22
|
-
##
|
|
30
|
+
## Which Raspberry Pi
|
|
31
|
+
|
|
32
|
+
Any of these work. What differs is only how long the install takes, and how much of a fight it is:
|
|
33
|
+
|
|
34
|
+
| Board | Install | Notes |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| **Pi 4** (or Pi 5, Pi 3) | About half an hour | The straightforward path. 64-bit, everything installs as ready-made binaries. |
|
|
37
|
+
| **Pi Zero 2 W** | Expect longer | 64-bit, so it should avoid the long compile below, but shares the Zero's 512 MB. Not yet tested. |
|
|
38
|
+
| **Pi Zero W** (the original) | Allow an afternoon | 32-bit ARMv6. One dependency has to be compiled — about 40 minutes — and 512 MB of RAM is not enough without adding swap. Tested and works. |
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
A Zero W runs the server perfectly well once installed. It is *installing* that is slow, because a
|
|
41
|
+
single 1 GHz core has to unpack several hundred packages and compile one of them.
|
|
42
|
+
|
|
43
|
+
### 0. What you need before you start
|
|
25
44
|
|
|
26
45
|
**Hardware**
|
|
27
46
|
|
|
28
|
-
* Raspberry Pi
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
|
|
47
|
+
* A Raspberry Pi, per the table above. Any RAM size — a running server uses around 250 MB.
|
|
48
|
+
(Measured on a 4 GB Pi 4: 231 MB in use with the server running.)
|
|
49
|
+
* A microSD card. 8 GB is enough for the system and software — a working install occupies about
|
|
50
|
+
5 GB — but sensor data accumulates on this card for as long as the server runs, so 16 GB or larger
|
|
51
|
+
is the safer choice. Class 10 / A1 or better.
|
|
52
|
+
* The official Raspberry Pi power supply for your board — USB-C on a Pi 4, micro-USB on a Zero.
|
|
53
|
+
Phone chargers frequently cause random reboots and corrupted SD cards — this is the single most
|
|
54
|
+
common cause of "it doesn't work".
|
|
32
55
|
* A way to write the SD card from your laptop: a built-in SD slot or a USB card reader.
|
|
33
56
|
* Note that you will often need an adapter from the SD format the Pi uses to the SD format of most laptop readers.
|
|
34
57
|
|
|
58
|
+
> **Pi Zero W:** its Wi-Fi is 2.4 GHz only, so it cannot see a 5 GHz-only network. It has no
|
|
59
|
+
> Ethernet socket either, so the cable trick in step 2 is unavailable — have the micro-HDMI cable
|
|
60
|
+
> and a keyboard to hand instead. Note micro-USB for power and a micro-USB OTG adapter for the
|
|
61
|
+
> keyboard: different cables from a Pi 4.
|
|
62
|
+
|
|
35
63
|
**Software and information**
|
|
36
64
|
|
|
37
65
|
* A laptop or desktop (Mac, Windows or Linux) with [Raspberry Pi Imager](https://www.raspberrypi.com/software/) installed.
|
|
@@ -48,19 +76,21 @@ see [README.md](https://github.com/mitra42/frugal-iot-server/blob/main/README.md
|
|
|
48
76
|
|
|
49
77
|
**Have these to hand in case the headless setup does not come up**
|
|
50
78
|
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
79
|
+
* An Ethernet cable from the Pi to your router — the simplest way in if the Pi does not appear on
|
|
80
|
+
the Wi-Fi, and you can then sort the Wi-Fi out over SSH (step 2).
|
|
81
|
+
* A micro-HDMI to HDMI cable plus a monitor, and a USB keyboard — for when the Pi is nowhere near the
|
|
82
|
+
router, or you want to see boot messages.
|
|
55
83
|
|
|
56
|
-
###
|
|
84
|
+
### 1. Write the operating system to the SD card
|
|
57
85
|
|
|
58
|
-
We use **Raspberry Pi OS Lite
|
|
86
|
+
We use **Raspberry Pi OS Lite** — the version with no desktop. The Pi is a server;
|
|
59
87
|
a desktop would only consume memory and SD card space.
|
|
60
88
|
|
|
61
89
|
1. Insert the SD card into your laptop and start Raspberry Pi Imager.
|
|
62
|
-
2. **Choose Device** →
|
|
90
|
+
2. **Choose Device** → your board.
|
|
63
91
|
3. **Choose OS** → *Raspberry Pi OS (other)* → *Raspberry Pi OS Lite (64-bit)*.
|
|
92
|
+
* **On a Pi Zero W choose *Raspberry Pi OS Lite (32-bit)*** — the 64-bit images will not boot on
|
|
93
|
+
its ARMv6 processor. (A Pi Zero **2** W is 64-bit, so it takes the 64-bit image like a Pi 4.)
|
|
64
94
|
4. **Choose Storage** → your SD card. Check the size shown matches your card — this erases it.
|
|
65
95
|
5. Click **Next**. When asked *"Would you like to apply OS customisation settings?"*, choose
|
|
66
96
|
**Edit Settings** — everything below depends on it.
|
|
@@ -72,9 +102,11 @@ a desktop would only consume memory and SD card space.
|
|
|
72
102
|
* Type the SSID exactly as the network broadcasts it, including capitals. Imager does not store
|
|
73
103
|
your Wi-Fi password; it converts it into a 64-character key using the SSID, so a mistyped SSID
|
|
74
104
|
produces a key that fails even though the password was right.
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
|
|
105
|
+
* If the Pi does not join the network, a mistyped SSID or password is much the likeliest cause -
|
|
106
|
+
neither is echoed back to you here, and Imager combines the two into a key, so a slip in either
|
|
107
|
+
looks the same later. Step 2 fixes it in a couple of minutes with `nmtui`.
|
|
108
|
+
* A WPA3 network cannot use the key Imager derives at all, so on one of those expect to finish the
|
|
109
|
+
Wi-Fi setup with `nmtui` regardless.
|
|
78
110
|
10. Enable SSH, either choose *Use password authentication* or paste your public key if you already use SSH keys.
|
|
79
111
|
11. Leave Raspberry Pi Connect off for now - feel free to experiment with this, as we haven't yet.
|
|
80
112
|
12. Confirm that you want to save settings and write to the card, and click through operating system prompts wanting to stop you !
|
|
@@ -86,7 +118,7 @@ Eject the card, put it in the Pi, connect power.
|
|
|
86
118
|
The first boot resizes the filesystem and reboots itself. Give it **two to three minutes** before
|
|
87
119
|
expecting it to answer.
|
|
88
120
|
|
|
89
|
-
###
|
|
121
|
+
### 2. Log in over the network
|
|
90
122
|
|
|
91
123
|
From your laptop's terminal:
|
|
92
124
|
|
|
@@ -96,6 +128,8 @@ ssh pi@frugaliot.local
|
|
|
96
128
|
|
|
97
129
|
Say `yes` to the fingerprint question, then give the password you set in Imager.
|
|
98
130
|
|
|
131
|
+
**If that logged you in, go straight to step 3.** The rest of this step is for when it did not.
|
|
132
|
+
|
|
99
133
|
**If `frugaliot.local` is not found**, the `.local` (mDNS) name is not reaching you. In order of ease:
|
|
100
134
|
|
|
101
135
|
* Wait another minute and try again — the Pi may still be on its first boot.
|
|
@@ -105,7 +139,7 @@ Say `yes` to the fingerprint question, then give the password you set in Imager.
|
|
|
105
139
|
up an address, and `ssh pi@frugaliot.local` then works over the cable. This is the least effort
|
|
106
140
|
way in if the Pi is within reach of the router, and once you are logged in you can sort the Wi-Fi
|
|
107
141
|
out over SSH with `nmtui` as below, no monitor or keyboard needed. Unplug the cable afterwards and
|
|
108
|
-
check that Wi-Fi alone still gets you in.
|
|
142
|
+
check that Wi-Fi alone still gets you in. (Not an option on a Pi Zero — no Ethernet socket.)
|
|
109
143
|
* Plug in the HDMI and keyboard, log in at the console, and run `ip addr` to read the IP address,
|
|
110
144
|
and `sudo journalctl -b | grep -i wpa` to see why Wi-Fi failed. Use this when the Pi is nowhere
|
|
111
145
|
near the router, or when you want to see boot messages.
|
|
@@ -141,7 +175,9 @@ the password — either way `nmtui` is the fix, and it is not worth more time th
|
|
|
141
175
|
(`sudo nmcli device wifi list` shows each nearby network's SSID and whether it is WPA2 or WPA3;
|
|
142
176
|
WPA3 cannot use a derived key at all.)
|
|
143
177
|
|
|
144
|
-
|
|
178
|
+
### 3. Update the operating system and install the prerequisites
|
|
179
|
+
|
|
180
|
+
Logged in, bring the system up to date and reboot:
|
|
145
181
|
|
|
146
182
|
```
|
|
147
183
|
sudo apt update
|
|
@@ -165,49 +201,138 @@ which you may not have the password for.
|
|
|
165
201
|
address does not change. Sensor nodes and phones then have something stable to talk to even where
|
|
166
202
|
`.local` names do not work.
|
|
167
203
|
|
|
168
|
-
|
|
204
|
+
Now the packages the server needs.
|
|
205
|
+
|
|
206
|
+
**On a Pi 4** (or any 64-bit board):
|
|
169
207
|
|
|
170
208
|
```
|
|
171
209
|
sudo apt install -y nodejs npm sqlite3 zsh
|
|
172
210
|
node -v
|
|
173
|
-
npm -v
|
|
174
211
|
```
|
|
175
212
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
213
|
+
**On a Pi Zero W**, three more packages, because a 32-bit machine has to compile part of the server
|
|
214
|
+
in step 4 and a Lite image has no compiler:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
sudo apt install -y nodejs npm sqlite3 zsh build-essential python3-dev python3-setuptools
|
|
218
|
+
node -v
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
What each is for:
|
|
222
|
+
|
|
223
|
+
* `nodejs` — the server needs **Node 18 or later**. Current Raspberry Pi OS (Debian 13, trixie)
|
|
224
|
+
provides 20.19.2, which is fine, on 32-bit as well as 64-bit. Older images shipped Node 18, also
|
|
225
|
+
fine. If `node -v` reports anything below 18, install a current version from
|
|
226
|
+
[NodeSource](https://github.com/nodesource/distributions) instead.
|
|
179
227
|
* `npm` — installs the server; it is a separate package from `nodejs` on Debian.
|
|
180
228
|
* `sqlite3` — the database the server keeps its accounts in.
|
|
181
|
-
* `zsh` — the setup commands in step
|
|
182
|
-
|
|
183
|
-
|
|
229
|
+
* `zsh` — the setup commands in step 6 are zsh scripts.
|
|
230
|
+
* `build-essential`, `python3-dev`, `python3-setuptools` — only needed where something has to be
|
|
231
|
+
compiled. `python3-setuptools` is the non-obvious one: the build uses node-gyp 8, which imports
|
|
232
|
+
Python's `distutils`, removed in Python 3.12, and setuptools puts an importable `distutils` back.
|
|
233
|
+
Without it step 4 ends in `ModuleNotFoundError: No module named 'distutils'`.
|
|
234
|
+
|
|
235
|
+
Now two settings that make the SD card last longer. A card wears out from being written to, and
|
|
236
|
+
these are the two places the system writes constantly without being asked to:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
# Cap the systemd journal, which by default is allowed to grow to a tenth of the card
|
|
240
|
+
sudo mkdir -p /etc/systemd/journald.conf.d
|
|
241
|
+
printf '[Journal]\nSystemMaxUse=16M\nSystemMaxFileSize=4M\n' | sudo tee /etc/systemd/journald.conf.d/frugal-iot.conf
|
|
242
|
+
sudo systemctl restart systemd-journald
|
|
243
|
+
|
|
244
|
+
# Swap out to the card only when there is genuinely no alternative
|
|
245
|
+
echo 'vm.swappiness=1' | sudo tee /etc/sysctl.d/99-frugal-iot-swappiness.conf
|
|
246
|
+
sudo sysctl --system | grep swappiness
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The `grep` should print `vm.swappiness = 1`. Both survive a reboot. There is more about what wears a
|
|
250
|
+
card out, and how to see whether yours is being written to hard, under
|
|
251
|
+
[Wear and tear on the SD card](#wear-and-tear-on-the-sd-card) — but nothing else there needs doing
|
|
252
|
+
during the install.
|
|
253
|
+
|
|
254
|
+
> **Pi Zero W: add swap before going on.** 512 MB is not enough to unpack what step 4 downloads, and
|
|
255
|
+
> running out does not fail cleanly — the board stops answering SSH and ping, and has to have its
|
|
256
|
+
> power pulled. Raspberry Pi OS enables zram, which is **not** sufficient here, because compressed
|
|
257
|
+
> RAM does not help when the working set is genuinely large. Add a real swap file (`dphys-swapfile`
|
|
258
|
+
> is not on the Trixie Lite image, so make it directly):
|
|
259
|
+
>
|
|
260
|
+
> ```
|
|
261
|
+
> sudo fallocate -l 2G /swapfile
|
|
262
|
+
> sudo chmod 600 /swapfile
|
|
263
|
+
> sudo mkswap /swapfile
|
|
264
|
+
> sudo swapon /swapfile
|
|
265
|
+
> free -h # should show 2.0Gi of swap
|
|
266
|
+
> echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
|
267
|
+
> ```
|
|
268
|
+
>
|
|
269
|
+
> **No reboot needed** — `swapon` takes effect at once, which the `free -h` line confirms. The
|
|
270
|
+
> `/etc/fstab` entry only matters later, so that the swap comes back after a reboot rather than
|
|
271
|
+
> having to be turned on by hand. Go straight on to step 4.
|
|
272
|
+
>
|
|
273
|
+
> Swapping to an SD card is slow, and wears it. That is the trade: the install takes longer, but it
|
|
274
|
+
> finishes instead of hanging. The `vm.swappiness=1` set above keeps the swap file available for
|
|
275
|
+
> emergencies like this one without it being used routinely afterwards.
|
|
276
|
+
|
|
277
|
+
### 4. Install the Frugal IoT server
|
|
184
278
|
|
|
185
279
|
The server is an npm package. Make a directory for this server to live in and install it there —
|
|
186
280
|
that directory will hold your configuration, your data, and your database, while npm looks after
|
|
187
281
|
the software itself underneath it in `node_modules`.
|
|
188
282
|
|
|
283
|
+
**On a Pi 4** (or any 64-bit board) — a few minutes, everything arrives as ready-made binaries and
|
|
284
|
+
nothing is compiled:
|
|
285
|
+
|
|
189
286
|
```
|
|
190
287
|
mkdir ~/frugal-iot
|
|
191
288
|
cd ~/frugal-iot
|
|
192
289
|
npm install frugal-iot-server
|
|
193
290
|
```
|
|
194
291
|
|
|
195
|
-
|
|
196
|
-
|
|
292
|
+
**On a Pi Zero W** — the extra flags make npm do one thing at a time, which lowers the peak memory
|
|
293
|
+
as well as being kinder to the SD card. This is the slow part; leave it running:
|
|
197
294
|
|
|
198
295
|
```
|
|
199
|
-
|
|
296
|
+
mkdir ~/frugal-iot
|
|
297
|
+
cd ~/frugal-iot
|
|
298
|
+
npm install --maxsockets 1 --no-audit --no-fund frugal-iot-server
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
That pulls in the web UI (`frugal-iot-client`) and the logger (`frugal-iot-logger`) as well.
|
|
302
|
+
|
|
303
|
+
> **Pi Zero W: check that the compiled part actually built.** npm can report success while leaving
|
|
304
|
+
> it out, and nothing else looks wrong when that happens — the server just refuses to start later.
|
|
305
|
+
>
|
|
306
|
+
> ```
|
|
307
|
+
> node -e "require('sqlite3'); console.log('sqlite3 native module loads OK')"
|
|
308
|
+
> ```
|
|
309
|
+
>
|
|
310
|
+
> If that throws `Could not locate the bindings file`, build just that package:
|
|
311
|
+
>
|
|
312
|
+
> ```
|
|
313
|
+
> time npm rebuild sqlite3 --foreground-scripts
|
|
314
|
+
> ```
|
|
315
|
+
>
|
|
316
|
+
> **This takes around 40 minutes on a Zero W** — it is compiling SQLite itself on one slow core. As
|
|
317
|
+
> long as it is producing output it is working; `--foreground-scripts` is what lets you see that. If
|
|
318
|
+
> the board locks up, pull the power, boot it, and run the same command again: work already done is
|
|
319
|
+
> kept, so each attempt gets further.
|
|
320
|
+
>
|
|
321
|
+
> Most of what is being installed is not Frugal IoT. The logger depends on `firebase-admin`, which
|
|
322
|
+
> brings in the Google Cloud SDK — around 40 packages and 30 MB — and that is what the board
|
|
323
|
+
> struggles with. It is only used by organizations that configure a `firebase:` section.
|
|
324
|
+
> TODO make that dependency optional in frugal-iot-logger, so small boards can skip it.
|
|
325
|
+
|
|
326
|
+
Then set the directory up:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
npx --no frugal-iot-init
|
|
200
330
|
```
|
|
201
331
|
|
|
202
332
|
This copies in the configuration files, creates the `data`, `ota` and `config.d/organizations`
|
|
203
333
|
directories, and creates the database. It never overwrites anything already there, so it is also
|
|
204
334
|
what you run after an upgrade to pick up newly added configuration.
|
|
205
335
|
|
|
206
|
-
> On a 64-bit Raspberry Pi OS this installs ready-made binaries and compiles nothing. If it ever
|
|
207
|
-
> does stop while building `sqlite3`, no binary was available for your platform, so install the
|
|
208
|
-
> compiler toolchain and try again: `sudo apt install -y build-essential python3` then
|
|
209
|
-
> `npm install frugal-iot-server`.
|
|
210
|
-
|
|
211
336
|
Everything from here on is run from `~/frugal-iot`, and `npx` is how you run the server's commands
|
|
212
337
|
without having to know where npm put them.
|
|
213
338
|
|
|
@@ -231,10 +356,10 @@ works on the Pi.
|
|
|
231
356
|
> `frugaliot.local` is known to work from a laptop and from an iPhone. Android phones generally
|
|
232
357
|
> cannot resolve `.local` names, so if you will view the dashboard on Android, put the Pi's IP
|
|
233
358
|
> address here instead — `broker: ws://192.168.1.42:9012`, using the address `ping -c1
|
|
234
|
-
> frugaliot.local` reported in step
|
|
359
|
+
> frugaliot.local` reported in step 3 — and reserve that address in your router if you can, so it
|
|
235
360
|
> does not change under you.
|
|
236
361
|
|
|
237
|
-
###
|
|
362
|
+
### 5. Install and configure the MQTT broker (Mosquitto)
|
|
238
363
|
|
|
239
364
|
Sensor nodes publish their readings to an MQTT broker; the Frugal IoT logger subscribes to it and
|
|
240
365
|
writes the readings to disk; the web UI subscribes to it to show live values. On an offline Pi,
|
|
@@ -256,16 +381,29 @@ sudo cp extras/mosquitto.conf /etc/mosquitto/conf.d/frugal-iot.conf
|
|
|
256
381
|
(Everything in `/etc/mosquitto/conf.d/` is read in addition to the packaged
|
|
257
382
|
`/etc/mosquitto/mosquitto.conf`, which keeps its own settings for logging and persistence.)
|
|
258
383
|
|
|
384
|
+
That file also turns off the broker's per-connection logging, because a node on a weak signal
|
|
385
|
+
reconnects constantly and each of those lines is a write to the SD card. Nothing is lost — the
|
|
386
|
+
readings themselves are recorded by the server, and everything else the broker says, including why
|
|
387
|
+
it refused to start, still goes to `/var/log/mosquitto/mosquitto.log`. If you are chasing a node
|
|
388
|
+
that keeps dropping off the network, comment out `connection_messages false` and restart the broker.
|
|
389
|
+
|
|
259
390
|
That configuration names a password file, and Mosquitto will not start if the file is missing, so
|
|
260
|
-
create an empty one. The accounts inside it get created for you in the next step
|
|
261
|
-
`addorganization.zsh` — which runs as you rather than as root, hence the ownership:
|
|
391
|
+
create an empty one. The accounts inside it get created for you in the next step:
|
|
262
392
|
|
|
263
393
|
```
|
|
264
|
-
sudo
|
|
265
|
-
sudo chown ${USER}:mosquitto /etc/mosquitto/mosquitto_passwords
|
|
266
|
-
sudo chmod 640 /etc/mosquitto/mosquitto_passwords
|
|
394
|
+
sudo install -o mosquitto -g mosquitto -m 600 /dev/null /var/lib/mosquitto/passwords
|
|
267
395
|
```
|
|
268
396
|
|
|
397
|
+
That makes an empty file belonging to the `mosquitto` user, readable by nobody else — one command
|
|
398
|
+
instead of a `touch`, a `chown` and a `chmod`.
|
|
399
|
+
|
|
400
|
+
> The ownership matters, and is easy to get wrong. Mosquitto warns unless the password file belongs
|
|
401
|
+
> to whoever opened it, and the broker runs as the `mosquitto` user — so the file belongs to
|
|
402
|
+
> `mosquitto`, and it lives under `/var/lib/mosquitto` (which that user owns) rather than
|
|
403
|
+
> `/etc/mosquitto` (which root owns). `mosquitto_passwd` also writes a temporary backup file
|
|
404
|
+
> alongside it, so it needs to write to that directory too, not just to the file. Step 6 runs it as
|
|
405
|
+
> the right user for you.
|
|
406
|
+
|
|
269
407
|
Start the broker and have it start at every boot:
|
|
270
408
|
|
|
271
409
|
```
|
|
@@ -293,19 +431,24 @@ mosquitto_sub -h localhost -u nobody -P wrong -t '#'
|
|
|
293
431
|
```
|
|
294
432
|
|
|
295
433
|
`Connection Refused: not authorised` is the **success** case here — the broker answered and
|
|
296
|
-
requires an account. There are no accounts yet; step
|
|
434
|
+
requires an account. There are no accounts yet; step 6 creates the first one, and there is a
|
|
297
435
|
fuller test at the end of it.
|
|
298
436
|
|
|
299
|
-
|
|
437
|
+
> If Mosquitto did not start, `npx --no frugal-iot-diagnostic` will tell you why in one step — most often
|
|
438
|
+
> that the password file its configuration names does not exist. Note that `systemctl status` and
|
|
439
|
+
> the journal only show an exit code; the actual reason is in Mosquitto's own log, which the
|
|
440
|
+
> diagnostic reads for you. See [When something does not work](#when-something-does-not-work).
|
|
300
441
|
|
|
301
|
-
|
|
442
|
+
### 6. Create your accounts and your organization
|
|
443
|
+
|
|
444
|
+
The database was created by `npx --no frugal-iot-init` in step 4, holding two accounts. One is
|
|
302
445
|
`everyone`, which nobody logs in as — it exists so that permissions granted to all logged-in users
|
|
303
446
|
have somewhere to live. The other is `superuser`, this server's administrator, which is given admin
|
|
304
447
|
rights over every organization you create. It starts with no password and cannot be logged into
|
|
305
448
|
until you give it one:
|
|
306
449
|
|
|
307
450
|
```
|
|
308
|
-
npx frugal-iot-setpassword superuser "<a-good-password>"
|
|
451
|
+
npx --no frugal-iot-setpassword superuser "<a-good-password>"
|
|
309
452
|
```
|
|
310
453
|
|
|
311
454
|
Use the same command later if you ever need to reset a password — for `superuser` or for any
|
|
@@ -314,19 +457,18 @@ other account.
|
|
|
314
457
|
Frugal IoT groups devices as **organization → project → device**. Create yours:
|
|
315
458
|
|
|
316
459
|
```
|
|
317
|
-
npx frugal-iot-addorganization
|
|
460
|
+
npx --no frugal-iot-addorganization myfarm "My Farm" you@example.com +61123456789 "<broker-password>"
|
|
318
461
|
```
|
|
319
462
|
|
|
320
463
|
The arguments are: organization id, display name, your email, your phone (`+` and digits only),
|
|
321
|
-
and a password. That one command writes `config.d/organizations/
|
|
322
|
-
named after the organization (`
|
|
464
|
+
and a password. That one command writes `config.d/organizations/myfarm.yaml`, creates a login account
|
|
465
|
+
named after the organization (`myfarm`), grants it admin rights, creates its OTA directory, **and adds
|
|
323
466
|
the organization's account to the broker's password file** — which is why the broker had to be
|
|
324
467
|
installed first.
|
|
325
468
|
|
|
326
|
-
* **Organization id `
|
|
469
|
+
* **Organization id `myfarm`** — must be 1–10 lower-case letters or digits. It becomes the first part
|
|
327
470
|
of every MQTT topic, so it must match what your sensor nodes are configured to publish to.
|
|
328
|
-
|
|
329
|
-
* **The password** goes into `config.d/organizations/dev.yaml` as `mqtt_password` and into the
|
|
471
|
+
* **The password** goes into `config.d/organizations/myfarm.yaml` as `mqtt_password` and into the
|
|
330
472
|
broker's password file, so it is a *machine* credential: the server's logger, your sensor nodes,
|
|
331
473
|
and any browser showing this organization's dashboard all authenticate to the broker with it.
|
|
332
474
|
Treat it as shared, not personal.
|
|
@@ -337,45 +479,47 @@ Tell Mosquitto to re-read the password file, so the new account works:
|
|
|
337
479
|
sudo systemctl restart mosquitto
|
|
338
480
|
```
|
|
339
481
|
|
|
340
|
-
**Give your login its own password.** That command set the `
|
|
482
|
+
**Give your login its own password.** That command set the `myfarm` *web login* password to the same
|
|
341
483
|
string as the broker password. They serve completely different purposes, so change the login one
|
|
342
484
|
now to something only you know — the broker credential is unaffected, and nothing needs to be kept
|
|
343
485
|
in step:
|
|
344
486
|
|
|
345
487
|
```
|
|
346
|
-
npx frugal-iot-setpassword
|
|
488
|
+
npx --no frugal-iot-setpassword myfarm "<your-own-login-password>"
|
|
347
489
|
```
|
|
348
490
|
|
|
349
491
|
**Now the full broker test.** In your SSH session subscribe as the organization, using the broker
|
|
350
492
|
password you chose above:
|
|
351
493
|
|
|
352
494
|
```
|
|
353
|
-
mosquitto_sub -h localhost -u
|
|
495
|
+
mosquitto_sub -h localhost -u myfarm -P '<broker-password>' -t '#' -v
|
|
354
496
|
```
|
|
355
497
|
|
|
356
498
|
It should sit there silently — no error, no exit. Open a **second** SSH session to the Pi and
|
|
357
499
|
publish something:
|
|
358
500
|
|
|
359
501
|
```
|
|
360
|
-
mosquitto_pub -h localhost -u
|
|
502
|
+
mosquitto_pub -h localhost -u myfarm -P '<broker-password>' -t 'myfarm/test/hello' -m '42'
|
|
361
503
|
```
|
|
362
504
|
|
|
363
|
-
`
|
|
505
|
+
`myfarm/test/hello 42` appearing in the first window proves the account, the password file and the
|
|
364
506
|
port 1883 listener your sensor nodes use are all working. The WebSocket listener on 9012 gets
|
|
365
|
-
exercised by the browser in step
|
|
507
|
+
exercised by the browser in step 7. Leave the subscriber running if you like — it is a useful
|
|
366
508
|
window onto what your nodes are doing. (`Ctrl-C` stops it.)
|
|
367
509
|
|
|
368
510
|
If you get `Connection Refused: not authorised`, the password does not match the one in
|
|
369
|
-
`config.d/organizations/
|
|
511
|
+
`config.d/organizations/myfarm.yaml`, or Mosquitto has not re-read the file since it changed.
|
|
512
|
+
`npx --no frugal-iot-diagnostic` checks this for every organization you have, and reports which ones the
|
|
513
|
+
broker actually accepts.
|
|
370
514
|
|
|
371
|
-
###
|
|
515
|
+
### 7. Start the server by hand and check it
|
|
372
516
|
|
|
373
517
|
From your install directory — `npx` looks for the server in the current directory's `node_modules`,
|
|
374
518
|
so this only works there:
|
|
375
519
|
|
|
376
520
|
```
|
|
377
521
|
cd ~/frugal-iot
|
|
378
|
-
npx frugal-iot-server
|
|
522
|
+
npx --no frugal-iot-server
|
|
379
523
|
```
|
|
380
524
|
|
|
381
525
|
> If npx answers with `Need to install the following packages: frugal-iot-server` and asks to
|
|
@@ -388,7 +532,7 @@ It lists each configuration file as it reads it, then:
|
|
|
388
532
|
readYamlConfigFile ./config.yaml
|
|
389
533
|
readYamlConfigDir ./config.d
|
|
390
534
|
... one line per configuration file ...
|
|
391
|
-
Broker ws://frugaliot.local:9012 - organizations:
|
|
535
|
+
Broker ws://frugaliot.local:9012 - organizations: myfarm
|
|
392
536
|
Doing OTA updates at /ota_update from /home/pi/frugal-iot/ota
|
|
393
537
|
Serving /node_modules from ./node_modules
|
|
394
538
|
User Database exists
|
|
@@ -400,16 +544,16 @@ Mounted API routes at /api
|
|
|
400
544
|
Added API error handler
|
|
401
545
|
Serving /data from ./data
|
|
402
546
|
Server starting on port 8080
|
|
403
|
-
mqtt
|
|
404
|
-
mqtt
|
|
405
|
-
Subscribing topic
|
|
547
|
+
mqtt myfarm connecting
|
|
548
|
+
mqtt myfarm connect
|
|
549
|
+
Subscribing topic myfarm/# 0
|
|
406
550
|
```
|
|
407
551
|
|
|
408
552
|
Check the `Broker` line names your own broker and your organization. The lines that matter most are
|
|
409
|
-
the last three: `mqtt
|
|
410
|
-
`Subscribing topic
|
|
411
|
-
`mqtt
|
|
412
|
-
`config.d/mqtt.yaml` and that the password in `config.d/organizations/
|
|
553
|
+
the last three: `mqtt myfarm connect` means the server reached the broker and authenticated, and
|
|
554
|
+
`Subscribing topic myfarm/#` means it is listening for your nodes. If instead you see repeated
|
|
555
|
+
`mqtt myfarm close`, `offline`, or `Not authorized`, the broker URL or the password is wrong — recheck
|
|
556
|
+
`config.d/mqtt.yaml` and that the password in `config.d/organizations/myfarm.yaml` matches the `myfarm`
|
|
413
557
|
broker account.
|
|
414
558
|
|
|
415
559
|
Once nodes are reporting, each reading is logged as it arrives, so this output keeps scrolling.
|
|
@@ -426,7 +570,7 @@ http://frugaliot.local:8080
|
|
|
426
570
|
> local networks"* the first time. **Allow it** — without that permission the browser cannot look up
|
|
427
571
|
> `frugaliot.local`, nor reach the broker at that name, so the page and the live data both fail.
|
|
428
572
|
|
|
429
|
-
You land on the Frugal IoT home page. Click **Dashboard**, and log in as username `
|
|
573
|
+
You land on the Frugal IoT home page. Click **Dashboard**, and log in as username `myfarm` with the
|
|
430
574
|
login password you set with `frugal-iot-setpassword` — not the broker password. (`superuser` and its
|
|
431
575
|
password work too.)
|
|
432
576
|
|
|
@@ -438,12 +582,17 @@ actually resolve: a phone that cannot look up `.local` names needs the Pi's IP a
|
|
|
438
582
|
|
|
439
583
|
Until a sensor node reports in there will be no data to look at, but the dashboard should load.
|
|
440
584
|
|
|
585
|
+
> Anything wrong here — the server not starting, `mqtt myfarm close` instead of `connect`, the page not
|
|
586
|
+
> loading, the MQTT status not reaching *connected* — is worth a `npx --no frugal-iot-diagnostic` in
|
|
587
|
+
> another terminal before digging in by hand. It tests the same chain from the Pi's side: broker
|
|
588
|
+
> logins, the three ports, and the web server.
|
|
589
|
+
|
|
441
590
|
Stop the server with `Ctrl-C` before continuing.
|
|
442
591
|
|
|
443
|
-
###
|
|
592
|
+
### 8. Run the server as a service
|
|
444
593
|
|
|
445
594
|
So that it starts automatically at boot and restarts if it crashes. The file that
|
|
446
|
-
`npx frugal-iot-init` put in `extras/` already describes this installation — user `pi`, installed
|
|
595
|
+
`npx --no frugal-iot-init` put in `extras/` already describes this installation — user `pi`, installed
|
|
447
596
|
into `/home/pi/frugal-iot` — so it needs no editing:
|
|
448
597
|
|
|
449
598
|
```
|
|
@@ -462,7 +611,7 @@ systemctl status frugaliot
|
|
|
462
611
|
> `sudo systemctl restart frugaliot`. `WorkingDirectory` is the important one: it is where the
|
|
463
612
|
> server looks for its configuration and database.
|
|
464
613
|
|
|
465
|
-
To watch its log output, which is where the `mqtt
|
|
614
|
+
To watch its log output, which is where the `mqtt myfarm connect` and incoming-reading messages now go:
|
|
466
615
|
|
|
467
616
|
```
|
|
468
617
|
journalctl -u frugaliot -f
|
|
@@ -471,7 +620,7 @@ journalctl -u frugaliot -f
|
|
|
471
620
|
Reboot the Pi (`sudo reboot`), wait a couple of minutes, and check `http://frugaliot.local:8080`
|
|
472
621
|
still answers. Your server is now installed.
|
|
473
622
|
|
|
474
|
-
###
|
|
623
|
+
### 9. Point your sensor nodes at the Pi
|
|
475
624
|
|
|
476
625
|
Your ESP8266/ESP32 nodes are told which broker to use in their sketch — `main.cpp`, or the `.ino`
|
|
477
626
|
file if you build in the Arduino IDE. Look for a line like:
|
|
@@ -483,29 +632,29 @@ frugal_iot.configure_mqtt("frugaliot.naturalinnovation.org", "dev", "public");
|
|
|
483
632
|
and point it at your Pi instead:
|
|
484
633
|
|
|
485
634
|
```cpp
|
|
486
|
-
frugal_iot.configure_mqtt("frugaliot.local", "
|
|
635
|
+
frugal_iot.configure_mqtt("frugaliot.local", "myfarm", "<broker-password>");
|
|
487
636
|
```
|
|
488
637
|
|
|
489
638
|
The three arguments are the broker's host, the organization, and that organization's broker
|
|
490
|
-
password. The organization must be the one you created in step
|
|
639
|
+
password. The organization must be the one you created in step 6, because it is the first part of
|
|
491
640
|
every topic the node publishes to, and the password is the *broker* password from that step — not
|
|
492
641
|
the login password. Then rebuild and flash the node as usual.
|
|
493
642
|
|
|
494
643
|
> If the node does not connect, try the Pi's IP address in place of `frugaliot.local`. Resolving
|
|
495
644
|
> `.local` names needs mDNS support in the firmware, which is not something this guide has
|
|
496
|
-
> confirmed; an IP address avoids the question entirely, which is why step
|
|
645
|
+
> confirmed; an IP address avoids the question entirely, which is why step 3 suggests reserving one
|
|
497
646
|
> for the Pi in your router.
|
|
498
647
|
|
|
499
|
-
You can confirm nodes are reporting without involving the UI, using the subscriber from step
|
|
648
|
+
You can confirm nodes are reporting without involving the UI, using the subscriber from step 6:
|
|
500
649
|
|
|
501
650
|
```
|
|
502
|
-
mosquitto_sub -h localhost -u
|
|
651
|
+
mosquitto_sub -h localhost -u myfarm -P '<broker-password>' -t '#' -v
|
|
503
652
|
```
|
|
504
653
|
|
|
505
654
|
Every reading from every node should scroll past. Seeing anything here also proves the broker's
|
|
506
655
|
port 1883 is reachable from off the Pi, which is what the nodes need.
|
|
507
656
|
|
|
508
|
-
###
|
|
657
|
+
### 10. HTTPS and over-the-air firmware updates
|
|
509
658
|
|
|
510
659
|
**To be written.** Everything above gives you a plain HTTP server on your local network, which is
|
|
511
660
|
all an offline installation needs. HTTPS matters for two things:
|
|
@@ -525,6 +674,16 @@ network and everything is correct — which is what you will see during this ins
|
|
|
525
674
|
cannot: Raspberry Pi OS saves the time periodically and restores that value at boot, so after a
|
|
526
675
|
power cut the Pi comes up believing it is whenever it last saved, and the gap never gets made up.
|
|
527
676
|
|
|
677
|
+
To see whether the Pi's clock is actually right at any moment:
|
|
678
|
+
|
|
679
|
+
```
|
|
680
|
+
timedatectl
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
`System clock synchronized: yes` means it has reached a time server and the clock is trustworthy.
|
|
684
|
+
`no`, with `NTP service: active`, means it is trying but has not succeeded — normal on a Pi with no
|
|
685
|
+
route to the internet, and the point at which the timestamps below become a concern.
|
|
686
|
+
|
|
528
687
|
What that affects:
|
|
529
688
|
|
|
530
689
|
* **Logged data is stamped with the wrong time**, so graphs and history drift after each power cut.
|
|
@@ -538,35 +697,133 @@ it whenever its own clock looks implausible (a date far in the past). Not accura
|
|
|
538
697
|
but close enough for sensor data.
|
|
539
698
|
|
|
540
699
|
---
|
|
700
|
+
### Wear and tear on the SD card
|
|
701
|
+
|
|
702
|
+
SD cards wear out from being written to, and a server recording sensor readings writes all the time.
|
|
703
|
+
We have not yet seen a card fail, but plan for one eventually: keep a copy of `config.d/` and
|
|
704
|
+
`frugal-iot.db` somewhere else, and treat the readings in `data/` as valuable but not irreplaceable.
|
|
705
|
+
|
|
706
|
+
A new installation is set up to write as little as it reasonably can, and the settings are worth
|
|
707
|
+
knowing about, because turning one of them back on for debugging and forgetting is easy to do:
|
|
708
|
+
|
|
709
|
+
| What | Where | Shipped as |
|
|
710
|
+
| ---- | ----- | ---------- |
|
|
711
|
+
| A line logged for every MQTT message received | `verbose:` in `config.d/logger.yaml` | `false` |
|
|
712
|
+
| Readings held in memory and written out periodically instead of one at a time | `flushseconds:` in `config.d/logger.yaml` | `300` (5 minutes) |
|
|
713
|
+
| A line logged for every web request | `morgan:` in `config.d/server.yaml` | `false` |
|
|
714
|
+
| Old readings compressed, and deleted if the disk fills | `housekeeping:` in `config.d/server.yaml` | compress after 2 days, never delete, keep 10% free |
|
|
715
|
+
| A line logged for every device connect and disconnect | `connection_messages` in `extras/mosquitto.conf` | `false` |
|
|
716
|
+
| A capped systemd journal, and swapping only as a last resort | `/etc/systemd/journald.conf.d/` and `/etc/sysctl.d/`, both set in step 3 | 16 MB journal, `vm.swappiness=1` |
|
|
717
|
+
|
|
718
|
+
Nothing in that table needs doing — step 3 and step 5 set all of it up. It is here because turning
|
|
719
|
+
one of them back on for debugging and then forgetting is easy to do.
|
|
720
|
+
|
|
721
|
+
`flushseconds` is the one with a cost attached: readings that have not been written out yet are only
|
|
722
|
+
in memory, so pulling the power loses up to five minutes of them. Stopping the server properly
|
|
723
|
+
(`sudo service frugaliot stop`, or a restart) writes them out first, and so does looking at a graph.
|
|
724
|
+
|
|
725
|
+
On a Pi 4 there should be very little swapping in any case — the server and Mosquitto together are a
|
|
726
|
+
small load for 1 GB or more. The Pi Zero W is the one to watch, since step 3 adds a 2 GB swap file to
|
|
727
|
+
get through the install. To see what is actually happening on your board:
|
|
728
|
+
|
|
729
|
+
```
|
|
730
|
+
cd ~/frugal-iot
|
|
731
|
+
npx --no frugal-iot-diagnostic
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
and read the **Wear on the SD card** section, which reports how much has been written since boot,
|
|
735
|
+
whether the machine is swapping, and whether each of the settings above is in force. Run it twice a
|
|
736
|
+
few days apart — the interesting number is the rate, not the total.
|
|
737
|
+
|
|
738
|
+
## When something does not work
|
|
739
|
+
|
|
740
|
+
From your install directory:
|
|
741
|
+
|
|
742
|
+
```
|
|
743
|
+
cd ~/frugal-iot
|
|
744
|
+
npx --no frugal-iot-diagnostic
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
It only looks — it changes nothing — and it ends with a **Summary** of anything it recognises as
|
|
748
|
+
broken. It covers most of the checks scattered through this guide, in one pass:
|
|
749
|
+
|
|
750
|
+
* the machine, the OS, free memory and disk, and whether the clock is synchronized
|
|
751
|
+
* the versions of node, npm, sqlite3, mosquitto, and of the three Frugal IoT packages
|
|
752
|
+
* what this directory holds: configuration, database, accounts, organizations
|
|
753
|
+
* Mosquitto's configuration, **which password file it names and whether that file exists**, who owns
|
|
754
|
+
it, and the accounts in it
|
|
755
|
+
* whether Mosquitto and the `frugaliot` service are running, with the last lines of the journal
|
|
756
|
+
**and of Mosquitto's own log**, which is where its startup errors actually appear
|
|
757
|
+
* whether the broker refuses a wrong password, and accepts each organization's real one
|
|
758
|
+
* whether ports 1883, 9012 and 8080 are listening, and whether the web server answers
|
|
759
|
+
* whether the broker host in `config.d/mqtt.yaml` resolves from this machine
|
|
760
|
+
* how much data the logger has written
|
|
761
|
+
|
|
762
|
+
Two things to know:
|
|
763
|
+
|
|
764
|
+
* Mosquitto's log belongs to the `mosquitto` user. The script reads it with `sudo` where it can; if
|
|
765
|
+
it says it could not, run the whole thing as `sudo npx --no frugal-iot-diagnostic`.
|
|
766
|
+
* The output is safe to paste into a bug report. Passwords are deliberately not printed — the
|
|
767
|
+
password file is listed by account name only, and organizations by name.
|
|
768
|
+
|
|
769
|
+
If you have not reached step 4 yet, the command does not exist. Copy
|
|
770
|
+
[scripts/diagnostic.zsh](https://github.com/mitra42/frugal-iot-server/blob/main/scripts/diagnostic.zsh)
|
|
771
|
+
to the Pi and run `zsh diagnostic.zsh` instead.
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
## Upgrading
|
|
541
776
|
|
|
542
|
-
|
|
777
|
+
To move an existing server to a newer release, from the directory you installed into:
|
|
543
778
|
|
|
544
|
-
|
|
545
|
-
|
|
779
|
+
```
|
|
780
|
+
cd ~/frugal-iot
|
|
781
|
+
npm update frugal-iot-server
|
|
782
|
+
npx --no frugal-iot-init
|
|
783
|
+
sudo systemctl restart frugaliot
|
|
784
|
+
```
|
|
546
785
|
|
|
547
|
-
|
|
786
|
+
Taking those in turn:
|
|
548
787
|
|
|
549
|
-
*
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
*
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
788
|
+
* `npm update` fetches the new version of the server, and of the client and logger it depends on.
|
|
789
|
+
* `frugal-iot-init` adds any configuration file or directory the new version expects and you do not
|
|
790
|
+
have yet. It never changes files you already have, so your settings, database and data are safe.
|
|
791
|
+
* `systemctl restart frugaliot` is what actually puts the new version into service — without it the
|
|
792
|
+
old one keeps running from memory, and nothing appears to have changed. (Skip this if you are
|
|
793
|
+
running the server by hand rather than as a service; stop it with `Ctrl-C` and start it again.)
|
|
794
|
+
|
|
795
|
+
Check it came back up, and is running the version you expect:
|
|
796
|
+
|
|
797
|
+
```
|
|
798
|
+
systemctl status frugaliot
|
|
799
|
+
journalctl -u frugaliot -n 30
|
|
800
|
+
npm ls frugal-iot-server
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
`frugal-iot-init` leaves your files alone, so watch its output for a section headed **"These files
|
|
804
|
+
were left as you have them, but this release ships a different version"**. It gives you the `diff`
|
|
805
|
+
command for each. That matters most for the files you copy somewhere else — a changed
|
|
806
|
+
`extras/mosquitto.conf` or `extras/frugaliot.service` does nothing until you install it again:
|
|
807
|
+
|
|
808
|
+
```
|
|
809
|
+
sudo cp extras/mosquitto.conf /etc/mosquitto/conf.d/frugal-iot.conf && sudo systemctl restart mosquitto
|
|
810
|
+
sudo cp extras/frugaliot.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl restart frugaliot
|
|
811
|
+
```
|
|
557
812
|
|
|
558
|
-
|
|
813
|
+
> It does not compare `config.yaml`, `config.d/mqtt.yaml`, `config.d/logger.yaml` or
|
|
814
|
+
> `config.d/server.yaml`, because those hold your own settings and would differ every time. If a
|
|
815
|
+
> release note mentions a new setting in one of them, compare it yourself:
|
|
816
|
+
> `diff config.d/server.yaml node_modules/frugal-iot-server/config.d/server.yaml`
|
|
559
817
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
compiled from source — which is likely on ARMv6, since no ready-made binaries are published.
|
|
818
|
+
Because your own configuration is left alone, an upgraded server goes on behaving exactly as it did,
|
|
819
|
+
which for the settings under [Wear and tear on the SD card](#wear-and-tear-on-the-sd-card) means it
|
|
820
|
+
goes on writing as often as it did. A server that has been running since before those settings
|
|
821
|
+
existed keeps logging every message and every web request, and writing every reading as it arrives —
|
|
822
|
+
deliberately, since quietening somebody's server without being asked is not a thing an upgrade should
|
|
823
|
+
do. On a Pi, compare the two files above and copy across the settings you want.
|
|
567
824
|
|
|
568
|
-
|
|
569
|
-
|
|
825
|
+
Your organizations, accounts, database and logged data are untouched by an upgrade — they live in
|
|
826
|
+
this directory, not in `node_modules`.
|
|
570
827
|
|
|
571
828
|
---
|
|
572
829
|
|
|
@@ -576,28 +833,28 @@ Things this guide currently states with less confidence than the rest, to be res
|
|
|
576
833
|
following it on real hardware. Please correct them in place, and delete them from this list, as
|
|
577
834
|
they get settled.
|
|
578
835
|
|
|
579
|
-
**
|
|
836
|
+
**To check while installing**
|
|
580
837
|
|
|
581
|
-
1. **`.local` from an Android phone** (
|
|
838
|
+
1. **`.local` from an Android phone** (steps 3, 4) - confirmed working from a laptop (with the
|
|
582
839
|
local-network permission granted on a Mac) and from an iPhone. Android is expected to fail, which
|
|
583
|
-
is what the note in
|
|
840
|
+
is what the note in step 4 assumes; worth confirming on a real Android phone.
|
|
584
841
|
|
|
585
842
|
**Needs information I do not have**
|
|
586
843
|
|
|
587
|
-
2. **
|
|
844
|
+
2. **Pi Zero 2 W** - the Zero W notes come from a real install; the Zero 2 W is untested. Being
|
|
845
|
+
64-bit it should take the 64-bit image and avoid the `sqlite3` compile entirely, which is the slow
|
|
846
|
+
part, but it has the same 512 MB and so probably still needs the swap file in step 3.
|
|
588
847
|
3. **Bridging to the shared server** — the local broker could optionally bridge to
|
|
589
848
|
naturalinnovation.org so data also reaches the shared server. Not covered here; a later task.
|
|
590
|
-
4. **Organization naming** — this guide sets up exactly one organization named `
|
|
849
|
+
4. **Organization naming** — this guide sets up exactly one organization named `myfarm`, because that
|
|
591
850
|
is the node firmware's default. Is that the right default for a farm installation, or should the
|
|
592
851
|
guide encourage a meaningful organization id (which then has to be set in the node firmware too)?
|
|
593
|
-
5. **Upgrading an existing installation** — `npm update frugal-iot-server` followed by
|
|
594
|
-
`npx frugal-iot-init` should be all it takes, since init adds missing configuration without
|
|
595
|
-
touching what is there. Not yet tried on a server that has been running for a while.
|
|
596
852
|
|
|
597
|
-
|
|
853
|
+
## Tested on
|
|
598
854
|
|
|
599
|
-
|
|
855
|
+
What the guide has actually been proven against — add a row for each run:
|
|
600
856
|
|
|
601
|
-
| Date | Board | OS image | Node
|
|
602
|
-
| --- | --- | --- | --- | --- |
|
|
603
|
-
|
|
|
857
|
+
| Date | Board | OS image | Node | Server | Result |
|
|
858
|
+
| --- | --- | --- | --- | --- | --- |
|
|
859
|
+
| 2026-08-17 | Pi Zero W (original), 512 MB | Raspberry Pi OS Lite **32-bit**, Debian 13 (trixie), kernel 6.18.39+rpt-rpi-v6 | 20.19.2 and npm 9.2.0, both from `apt` — they run on ARMv6 | frugal-iot-server 0.3.5 from npm | Steps 1-8 completed. `sqlite3` had to be compiled: about 40 minutes, after `build-essential python3-dev python3-setuptools` (without setuptools it fails on `distutils`). A 2 GB swap file was required — zram alone was not enough and the board locked up hard without it — and `npm install` was run with `--maxsockets 1`. Step 9 (sensor nodes) not exercised on this board, but the broker publish/subscribe tests in step 6 passed. |
|
|
860
|
+
| 2026-08-16 | Pi 4 Model B, 4GB | Raspberryy Pi OS Lite 64-bit, Debian 13.6 (trixie) | 20.19.2 and npm 9.2.0, both from `apt` | frugal-iot-server 0.3.5 from npm | Steps 1-9 completed, plus upgrade over top. Dashboard reached over `frugaliot.local` from a Mac (Chrome, after allowing local network access) and from an iPhone, MQTT status *connected*. 10 (HTTPS/OTA) not exercised.
|