frugal-iot-server 0.3.8 → 0.3.9

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 CHANGED
@@ -40,42 +40,6 @@ Any of these work. What differs is only how long the install takes, and how much
40
40
  A Zero W runs the server perfectly well once installed. It is *installing* that is slow, because a
41
41
  single 1 GHz core has to unpack several hundred packages and compile one of them.
42
42
 
43
- ## The short way: one script
44
-
45
- Steps 3 to 8 below can be done for you. Once you can ssh into the Pi (steps 1 and 2, which need a
46
- person with an SD card):
47
-
48
- ```
49
- curl -fsSLO https://raw.githubusercontent.com/mitra42/frugal-iot-server/main/scripts/install-pi.sh
50
- bash install-pi.sh --org myfarm --name "My Farm" --email you@example.com --phone +61123456789
51
- ```
52
-
53
- It asks for anything it needs that you did not pass, says what it is doing as it goes, and stops at
54
- the first thing that fails - leaving a log, and telling you to run `frugal-iot-diagnostic`. Running
55
- it again after a failure carries on rather than starting over, which matters on a Pi Zero W where one
56
- step takes about 40 minutes. `--dry-run` checks the arguments and shows the plan without touching the
57
- machine.
58
-
59
- **Passwords** are asked for, not invented, unless you say otherwise: it prompts for each (twice, not
60
- echoed) and generates one if you just press Enter. Pass them as `--superuser-password`,
61
- `--login-password` and `--broker-password` to skip the prompts, `--random-passwords` to have all
62
- three generated, or `--yes` to ask nothing at all — which is what to use over ssh with no terminal.
63
- A password you chose is not written to the log; a generated one has to be, since otherwise you would
64
- have no way of knowing it.
65
-
66
- **It tells you whether a reboot is needed**, rather than leaving you to wonder — it notices a kernel
67
- or boot-firmware package in the upgrade, the images in `/boot` changing underneath it, and
68
- `/var/run/reboot-required`. If none of those happened it says so, and there is nothing more to do.
69
-
70
- Fetch it with `curl -O` and then run it, rather than piping curl into bash - piped, it has no
71
- terminal to ask questions at.
72
-
73
- It finishes with a live server and a tested broker. It cannot do step 9, pointing your nodes at it,
74
- because a node learns its broker by being flashed with it - so it prints the settings to give them.
75
- Nor step 10, HTTPS.
76
-
77
- The steps below are what it does, in the same order, if you would rather do it by hand or need to
78
- understand what went wrong.
79
43
 
80
44
  ---
81
45
  ### 0. What you need before you start
@@ -163,6 +127,7 @@ From your laptop's terminal:
163
127
  ```
164
128
  ssh pi@frugaliot.local
165
129
  ```
130
+ > **Pi Zero W:** This can take a long time to connect, try `ping frugaliot.local` first to check it is alive
166
131
 
167
132
  Say `yes` to the fingerprint question, then give the password you set in Imager.
168
133
 
@@ -213,6 +178,44 @@ the password — either way `nmtui` is the fix, and it is not worth more time th
213
178
  (`sudo nmcli device wifi list` shows each nearby network's SSID and whether it is WPA2 or WPA3;
214
179
  WPA3 cannot use a derived key at all.)
215
180
 
181
+ ## 3-8. The short way: one script
182
+
183
+ Steps 3 to 8 below can be done for you. Once you can ssh into the Pi (steps 1 and 2, which need a
184
+ person with an SD card):
185
+
186
+ ```
187
+ curl -fSLO https://raw.githubusercontent.com/mitra42/frugal-iot-server/main/scripts/install-pi.sh
188
+ bash install-pi.sh --org myfarm --name "My Farm" --email you@example.com --phone +61123456789
189
+ ```
190
+
191
+ It asks for anything it needs that you did not pass, says what it is doing as it goes, and stops at
192
+ the first thing that fails - leaving a log, and telling you to run `frugal-iot-diagnostic`. Running
193
+ it again after a failure carries on rather than starting over, which matters on a Pi Zero W where one
194
+ step takes about 40 minutes. `--dry-run` checks the arguments and shows the plan without touching the
195
+ machine.
196
+
197
+ **Passwords** are asked for, not invented, unless you say otherwise: it prompts for each (twice, not
198
+ echoed) and generates one if you just press Enter. Pass them as `--superuser-password`,
199
+ `--login-password` and `--broker-password` to skip the prompts, `--random-passwords` to have all
200
+ three generated, or `--yes` to ask nothing at all — which is what to use over ssh with no terminal.
201
+ A password you chose is not written to the log; a generated one has to be, since otherwise you would
202
+ have no way of knowing it.
203
+
204
+ **It tells you whether a reboot is needed**, rather than leaving you to wonder — it notices a kernel
205
+ or boot-firmware package in the upgrade, the images in `/boot` changing underneath it, and
206
+ `/var/run/reboot-required`. If none of those happened it says so, and there is nothing more to do.
207
+
208
+ Fetch it with `curl -O` and then run it, rather than piping curl into bash - piped, it has no
209
+ terminal to ask questions at.
210
+
211
+ It finishes with a live server and a tested broker. It cannot do step 9, pointing your nodes at it,
212
+ because a node learns its broker by being flashed with it - so it prints the settings to give them.
213
+ Nor step 10, HTTPS.
214
+
215
+ The steps below are what it does, in the same order, if you would rather do it by hand or need to
216
+ understand what went wrong, otherwise skip to Step 9.
217
+
218
+
216
219
  ### 3. Update the operating system and install the prerequisites
217
220
 
218
221
  Logged in, bring the system up to date and reboot:
@@ -692,6 +695,101 @@ mosquitto_sub -h localhost -u myfarm -P '<broker-password>' -t '#' -v
692
695
  Every reading from every node should scroll past. Seeing anything here also proves the broker's
693
696
  port 1883 is reachable from off the Pi, which is what the nodes need.
694
697
 
698
+ ### 9a. Optional: outgoing mail, so people can reset a forgotten password
699
+
700
+ Without this, a forgotten password can only be fixed by you, on the Pi, with
701
+ `npx --no frugal-iot-setpassword <username> <new-password>`. The login page's "Forgot password?"
702
+ link says "Password reset is not available on this server" rather than pretending to send anything.
703
+
704
+ An offline Pi cannot send mail at all, so skip this unless it has internet access.
705
+
706
+ Mail sent straight from a home broadband connection is almost always treated as spam, so this
707
+ relays through somebody else's SMTP server rather than sending directly. Gmail is the usual choice
708
+ and is written out in full below; any other provider works the same way.
709
+
710
+ #### With Gmail
711
+
712
+ Use a Google account you are willing to have the Pi send as. A separate account for the purpose is
713
+ better than your own mailbox — the password ends up in a file on an SD card in a shed.
714
+
715
+ **1. Turn on 2-Step Verification** on that account, at
716
+ <https://myaccount.google.com/signinoptions/twosv>.
717
+
718
+ This is not optional and it is where most people get stuck: **app passwords do not exist until
719
+ 2-Step Verification is on**. Until then the page in step 2 simply says the setting is not available,
720
+ without explaining why.
721
+
722
+ **2. Create an app password** at <https://myaccount.google.com/apppasswords>.
723
+
724
+ Type a name for it — anything you will recognise later, such as `Frugal IoT Pi` — and create it.
725
+ Google shows you **16 lowercase letters, in four groups of four**, once. Copy them now; you cannot
726
+ come back and read it again, only delete it and make another.
727
+
728
+ The groups are only there to make it readable. **Type it into the config with the spaces removed**,
729
+ as one 16-character word.
730
+
731
+ **3. Fill in `config.d/email.yaml`:**
732
+
733
+ ```yaml
734
+ host: smtp.gmail.com
735
+ port: 587
736
+ user: yourname@gmail.com
737
+ pass: "abcdefghijklmnop" # the 16 characters from step 2, spaces removed
738
+ from: Frugal IoT <yourname@gmail.com>
739
+ ```
740
+
741
+ Things that catch people out with Gmail specifically:
742
+
743
+ * **`from:` must be the same address as `user:`.** Gmail rewrites the sender to the account you
744
+ authenticated as, so a different address here does not fail — it quietly arrives as something
745
+ else, which is harder to diagnose than an error. (An address you have set up under Gmail's
746
+ "Send mail as" is the one exception.)
747
+ * **`user:` is the full address**, including `@gmail.com`, not just the part before it.
748
+ * **`Username and Password not accepted`** in the server's log means the login password was used
749
+ instead of an app password. Gmail has not accepted account passwords over SMTP for years.
750
+ * **Port 465 also works** if 587 is blocked where the Pi is; the software works out the encryption
751
+ from the port number, so change nothing else.
752
+ * **A free Gmail account can send around 500 messages a day.** Password resets will not come close.
753
+ * **Google Workspace administrators can switch app passwords off** for a whole domain. If step 2
754
+ offers you nothing on a work account, that is why, and you will need a real SMTP relay instead.
755
+
756
+ #### With any other provider
757
+
758
+ The same four settings, with that provider's SMTP host:
759
+
760
+ ```yaml
761
+ host: smtp.example.org
762
+ port: 587 # 465 is implicit TLS, 587 and 25 are STARTTLS
763
+ user: frugaliot@example.org
764
+ pass: an-app-password-not-your-login-password
765
+ from: Frugal IoT <frugaliot@example.org>
766
+ ```
767
+
768
+ Fastmail, Zoho, Proton (via its bridge) and the rest all issue app passwords in much the same way,
769
+ and for the same reason: one leaking off a Pi then costs you one mailbox rather than the account.
770
+
771
+ #### Checking it, either way
772
+
773
+ Restart the server and look at its output:
774
+
775
+ * `Sending mail via smtp.gmail.com:587 as ...` — configured.
776
+ * `Not sending mail (no host/from in config.d/email.yaml) ...` — it did not find a `host` and a
777
+ `from`, so the reset link will say it is unavailable.
778
+
779
+ Then use "Forgot password?" on the login page with your own account. If the mail never arrives, the
780
+ reason is in the server's log — the page deliberately gives the same answer whether or not the
781
+ address is known to it, so it cannot be used to find out who has an account here.
782
+
783
+ Two more things worth knowing:
784
+
785
+ * `pass` sits in a file on the SD card in plain text. Give that mailbox nothing else to lose.
786
+ * If the Pi is behind a proxy that does not set `X-Forwarded-Host`, the link in the mail will point
787
+ at the wrong address. Set `baseurl: https://your.address` in the same file.
788
+
789
+ The reset code itself is stored nowhere — it is a hash of the account, its current password and the
790
+ time, valid between five and ten minutes and dead the moment it is used. There is no table to
791
+ maintain and nothing to clean up. Restarting the server invalidates any code already sent.
792
+
695
793
  ### 10. HTTPS and over-the-air firmware updates
696
794
 
697
795
  **To be written.** Everything above gives you a plain HTTP server on your local network, which is
@@ -726,9 +824,6 @@ It comes in three parts, and only the first is a one-off:
726
824
  * **11b — authorizing this Pi on that server.** One command, run there, once per Pi.
727
825
  * **11c — pointing this Pi at it.** One command, run here, once per Pi.
728
826
 
729
- If someone has already done 11a for the server you are bridging to — the usual case once the first
730
- Pi is working — **start at 11b**.
731
-
732
827
  **What you get, and what you do not.** While the link is up, readings appear on production within
733
828
  a second or so. While it is down, the Pi records everything as usual and production simply has a
734
829
  gap — the readings taken during an outage never reach it. That is a deliberate choice: the
@@ -740,8 +835,8 @@ takes effect when it reconnects.
740
835
 
741
836
  #### 11a. Preparing a production server to accept bridges
742
837
 
743
- Once per production server, not per Pi — and someone has probably already done it for
744
- `frugaliot.naturalinnovation.org`. If so, skip to 11b.
838
+ Once per production server, not per Pi — and if bridging to `frugaliot.naturalinnovation.org`
839
+ this has already been done. If so, skip to 11b.
745
840
 
746
841
  **Add a listener for bridges.** A Mosquitto bridge speaks MQTT or MQTT-over-TLS and cannot use
747
842
  WebSockets, so the existing `wss://` path that browsers and servers use cannot carry this. It needs
@@ -894,7 +989,7 @@ Once per Pi. Run the command 11b printed, from this installation's directory:
894
989
 
895
990
  ```
896
991
  cd ~/frugal-iot
897
- npx --no frugal-iot-addbridge-pi --org <org-id> --host <prod-host> --account bridge-<site-name>
992
+ npx --no frugal-iot-addbridge-pi <org-id> <prod-host> bridge-<site-name>
898
993
  ```
899
994
 
900
995
  It asks for the password rather than taking it on the command line, so it stays out of your shell
@@ -1060,7 +1155,11 @@ npx --no frugal-iot-clearretained 'myfarm/lotus/+/sht/temperture/#'
1060
1155
  ```
1061
1156
 
1062
1157
  Quote the pattern or the shell will expand it. That lists what is retained and changes nothing;
1063
- add `--delete` to the same command to remove it.
1158
+ add the word `delete` at the end of the same command to remove it.
1159
+
1160
+ > `delete` is a bare word rather than a `--delete` flag on purpose. npm parses the command line of
1161
+ > an `npx` invocation itself and swallows any `--flag` it does not recognise, so `--delete` would
1162
+ > never reach the script and it would quietly list instead of deleting.
1064
1163
 
1065
1164
  > Look before deleting. A node's `min`, `max`, `color` and `wired` settings are retained messages
1066
1165
  > too, and they are how the dashboard knows how to draw it — delete those and the node has to be
@@ -0,0 +1,23 @@
1
+ # Outgoing mail. Only used by the password reset, which is unavailable until this is filled in -
2
+ # the login page says so rather than pretending to have sent something.
3
+ #
4
+ # Leave it commented out on a server that should not send mail.
5
+ #
6
+ # For Gmail - the common case, written out step by step in INSTALLATION.md section 9a:
7
+ # 1. Turn on 2-Step Verification: https://myaccount.google.com/signinoptions/twosv
8
+ # App passwords do not exist until you do, which is where most people get stuck.
9
+ # 2. Create an app password: https://myaccount.google.com/apppasswords
10
+ # You get 16 lowercase letters in four groups of four, shown once. Remove the spaces.
11
+ # 3. "from" must be the same address as "user" - Gmail silently rewrites anything else.
12
+ #
13
+ # host: smtp.gmail.com
14
+ # port: 587 # 465 is implicit TLS, 587 and 25 are STARTTLS; secure: is derived from this
15
+ # user: yourname@gmail.com
16
+ # pass: "abcdefghijklmnop" # the app password, NOT your Google account password
17
+ # from: Frugal IoT <yourname@gmail.com>
18
+ #
19
+ # Any other provider is the same four settings with its own SMTP host.
20
+ #
21
+ # The reset email contains a link back to this server. Set baseurl if the server cannot work out
22
+ # its own public address from the request - behind a proxy that does not set X-Forwarded-Host, say.
23
+ # baseurl: https://frugaliot.example.org
@@ -59,5 +59,3 @@ soil:
59
59
  sonoff:
60
60
  # The relay is what someone wants to see; the control that drives it comes second.
61
61
  front: [relay/on, controlhysteresis]
62
- temp:
63
- front: [aht20/temperature, bmp280/pressure, controlhysteresis]
@@ -20,11 +20,89 @@ aht21:
20
20
  topics:
21
21
  - leaf: temperature
22
22
  - leaf: humidity
23
+ # The DS18B20 probes on an FF-OpenMPPT board - see frugal-iot-irrigation. Separate modules rather
24
+ # than one, because the three measure quite different things and want different ranges; the class
25
+ # is the same Sensor_DS18B20 as the `ds18b20` module below.
26
+ airtemp:
27
+ name: Air Temperature
28
+ topics:
29
+ - leaf: airtemp
30
+ leaf_from: temperature
31
+ name: Air Temperature
32
+ min: -20
33
+ max: 60
34
+ analog:
35
+ name: "Analog Out"
36
+ topics:
37
+ - leaf: volts
23
38
  battery:
24
39
  name: "Battery"
25
40
  insidefrugaliot: true
26
41
  topics:
27
42
  - leaf: battery
43
+ # How much of its rated capacity the battery still has, inferred from an overnight discharge.
44
+ # A trend over weeks, not a reading; see control_health.h. Named batteryhealth because `health` is
45
+ # already taken by the device's own reporting.
46
+ batteryhealth:
47
+ name: Battery Health
48
+ topics:
49
+ - leaf: health
50
+ leaf_from: percent
51
+ name: Health
52
+ duplicates:
53
+ significantdate: 86400000
54
+ significantvalue: 1
55
+ - leaf: state
56
+ leaf_from: controltext
57
+ name: State
58
+ rw: r
59
+ - leaf: soc
60
+ leaf_from: controlfloat
61
+ name: Charge
62
+ min: 0
63
+ max: 100
64
+ - leaf: capacity
65
+ leaf_from: controlfloat
66
+ name: Capacity Ah
67
+ min: 0
68
+ max: 500
69
+ wireable: false
70
+ - leaf: load
71
+ leaf_from: controlfloat
72
+ name: Average load A
73
+ min: 0
74
+ max: 50
75
+ wireable: false
76
+ - leaf: active
77
+ leaf_from: controlint
78
+ name: Irrigation active
79
+ min: 0
80
+ max: 16
81
+ - leaf: panelwatts
82
+ leaf_from: controlfloat
83
+ name: Panel watts
84
+ min: 0
85
+ max: 2000
86
+ wireable: false
87
+ - leaf: storageratio
88
+ leaf_from: controlfloat
89
+ name: Storage ratio
90
+ min: 0
91
+ max: 50
92
+ rw: r
93
+ wireable: false
94
+ - leaf: advice
95
+ leaf_from: controltext
96
+ name: Advice
97
+ rw: r
98
+ batttemp:
99
+ name: Battery Temperature
100
+ topics:
101
+ - leaf: batttemp
102
+ leaf_from: temperature
103
+ name: Battery Temperature
104
+ min: -20
105
+ max: 60
28
106
  bme280:
29
107
  name: "BME280"
30
108
  topics:
@@ -131,11 +209,11 @@ ens160:
131
209
  leaf_from: controlfloat
132
210
  name: Temperature
133
211
  max: 50
134
- color: red
212
+ color: "#ff0000"
135
213
  - leaf: humidity
136
214
  leaf_from: controlfloat
137
215
  name: Humidity
138
- color: blue
216
+ color: "#0000ff"
139
217
  - leaf: aqi
140
218
  - leaf: tvoc
141
219
  - leaf: eco2
@@ -177,6 +255,16 @@ health:
177
255
  topics:
178
256
  - leaf: wifibars
179
257
  - leaf: wifissid
258
+ # The charge controller's own heatsink. Either a DS18B20 or a pair of diodes read on an ADC pin,
259
+ # depending on the board - the reading means the same either way.
260
+ heatsink:
261
+ name: Heatsink Temperature
262
+ topics:
263
+ - leaf: heatsink
264
+ leaf_from: temperature
265
+ name: Heatsink Temperature
266
+ min: 0
267
+ max: 120
180
268
  ht:
181
269
  name: HT
182
270
  topics:
@@ -190,11 +278,64 @@ ina219:
190
278
  - leaf: current
191
279
  - leaf: power
192
280
  - leaf: load
281
+ irrigation:
282
+ name: Irrigation
283
+ topics:
284
+ - leaf: hour
285
+ leaf_from: controlint
286
+ name: Start hour
287
+ min: 0
288
+ max: 23
289
+ - leaf: minute
290
+ leaf_from: controlint
291
+ name: Start minute
292
+ min: 0
293
+ max: 59
294
+ - leaf: maxminutes
295
+ leaf_from: controlfloat
296
+ name: Max minutes per sector
297
+ min: 0
298
+ max: 120
299
+ - leaf: enabled
300
+ leaf_from: controlintoggle
301
+ name: Enabled
302
+ - leaf: tank
303
+ leaf_from: controlfloat
304
+ name: Tank level
305
+ color: "#0000ff"
306
+ - leaf: tankstart
307
+ leaf_from: controlfloat
308
+ name: Tank level to start
309
+ - leaf: tankempty
310
+ leaf_from: controlfloat
311
+ name: Tank level to stop
312
+ - leaf: power
313
+ leaf_from: controlintoggle
314
+ name: Power ok
315
+ wireable: true
316
+ - leaf: solar
317
+ leaf_from: controlintoggle
318
+ name: Input power
319
+ wireable: true
320
+ - leaf: pump
321
+ leaf_from: controlouttoggle
322
+ name: Pump
323
+ - leaf: active
324
+ leaf_from: controlint
325
+ name: Active sector
326
+ min: 0
327
+ max: 16
193
328
  lcd:
194
329
  summary: false # a message is not a reading
195
330
  name: LCD
196
331
  topics:
197
332
  - leaf: message
333
+ # The switched load output - OSPIT's pin 14 in its "load" role, opened by the low-voltage
334
+ # disconnect. An Actuator_Digital, so the same shape as `relay`.
335
+ load:
336
+ name: Load
337
+ topics:
338
+ - leaf: on
198
339
  ledbuiltin:
199
340
  name: LED
200
341
  slot: ledbuiltin
@@ -211,6 +352,96 @@ lux:
211
352
  name: Light meter
212
353
  topics:
213
354
  - leaf: lux
355
+ # Solar charge control - see frugal-iot-irrigation. `step` is the raw DAC value because that is
356
+ # unambiguous; `vmpp` is what the node PREDICTS that step asks the hardware for, which is a guess
357
+ # until it has been checked against a meter.
358
+ mppt:
359
+ name: Charge Control
360
+ topics:
361
+ - leaf: automatic
362
+ leaf_from: controlintoggle
363
+ name: Automatic
364
+ - leaf: state
365
+ leaf_from: controltext
366
+ name: State
367
+ rw: r
368
+ - leaf: profile
369
+ leaf_from: controlint
370
+ name: Battery type
371
+ min: 0
372
+ max: 3
373
+ wireable: false
374
+ - leaf: chargeend
375
+ leaf_from: controlfloat
376
+ name: Charge end
377
+ min: 10000
378
+ max: 16000
379
+ wireable: false
380
+ - leaf: tempcoeff
381
+ leaf_from: controlfloat
382
+ name: Temp coefficient
383
+ min: 0
384
+ max: 60
385
+ wireable: false
386
+ - leaf: hotcharge
387
+ leaf_from: controlfloat
388
+ name: Hot battery
389
+ min: 10000
390
+ max: 16000
391
+ wireable: false
392
+ - leaf: batttemp
393
+ leaf_from: controlfloat
394
+ name: Battery temp
395
+ min: -20
396
+ max: 60
397
+ - leaf: heatsink
398
+ leaf_from: controlfloat
399
+ name: Heatsink temp
400
+ min: 0
401
+ max: 120
402
+ - leaf: target
403
+ leaf_from: controlfloat
404
+ name: Target
405
+ min: 10000
406
+ max: 16000
407
+ rw: r
408
+ wireable: false
409
+ - leaf: step
410
+ leaf_from: controlint
411
+ name: DAC step
412
+ min: 0
413
+ max: 255
414
+ wireable: false
415
+ - leaf: panel
416
+ leaf_from: controlfloat
417
+ name: Panel
418
+ min: 0
419
+ max: 30000
420
+ - leaf: battery
421
+ leaf_from: controlfloat
422
+ name: Battery
423
+ min: 0
424
+ max: 16000
425
+ - leaf: voc
426
+ leaf_from: controlfloat
427
+ name: Open circuit
428
+ min: 0
429
+ max: 30000
430
+ rw: r
431
+ wireable: false
432
+ - leaf: vmpp
433
+ leaf_from: controlfloat
434
+ name: Panel target
435
+ min: 0
436
+ max: 30
437
+ rw: r
438
+ wireable: false
439
+ - leaf: dacvolts
440
+ leaf_from: controlfloat
441
+ name: DAC volts
442
+ min: 0
443
+ max: 3.3
444
+ rw: r
214
445
  ms5803:
215
446
  name: MS5803
216
447
  topics:
@@ -221,6 +452,25 @@ ota:
221
452
  insidefrugaliot: true
222
453
  topics:
223
454
  - leaf: key
455
+ panel:
456
+ name: Solar Panel
457
+ topics:
458
+ - leaf: panel
459
+ leaf_from: voltage
460
+ name: Panel Voltage
461
+ max: 30000
462
+ pcbtemp:
463
+ name: Board Temperature
464
+ topics:
465
+ - leaf: pcbtemp
466
+ leaf_from: temperature
467
+ name: Board Temperature
468
+ min: -20
469
+ max: 100
470
+ pump:
471
+ name: Pump
472
+ topics:
473
+ - leaf: on
224
474
  rain:
225
475
  name: Rain
226
476
  topics:
@@ -230,16 +480,93 @@ relay:
230
480
  name: Relay
231
481
  topics:
232
482
  - leaf: on
483
+ # One sector of an irrigation run - see modules "irrigation". A node with several sectors publishes
484
+ # sector1, sector2... and the client resolves those numbered instances back to this entry, so only
485
+ # the one definition is needed here however many sectors a node has.
486
+ sector:
487
+ name: Irrigation sector
488
+ topics:
489
+ - leaf: moisture
490
+ leaf_from: controlfloat
491
+ name: Moisture
492
+ color: "#a52a2a"
493
+ - leaf: target
494
+ leaf_from: controlfloat
495
+ name: Target
496
+ - leaf: enable
497
+ leaf_from: controlintoggle
498
+ name: Enable
499
+ - leaf: valve
500
+ leaf_from: controlouttoggle
501
+ name: Valve
233
502
  sht:
234
503
  name: SHT
235
504
  topics:
236
505
  - leaf: temperature
237
506
  - leaf: humidity
507
+ # State of charge, estimated from battery voltage - reporting only, never controlled from. See
508
+ # control_soc.h in frugal-iot-irrigation for what the estimate is and is not worth.
509
+ soc:
510
+ name: State of Charge
511
+ topics:
512
+ - leaf: soc
513
+ leaf_from: percent
514
+ name: Charge
515
+ duplicates:
516
+ significantdate: 900000
517
+ significantvalue: 1
518
+ - leaf: charging
519
+ leaf_from: controlouttoggle
520
+ name: Charging
521
+ - leaf: battery
522
+ leaf_from: controlfloat
523
+ name: Battery
524
+ min: 0
525
+ max: 16000
526
+ - leaf: panel
527
+ leaf_from: controlfloat
528
+ name: Panel
529
+ min: 0
530
+ max: 30000
531
+ - leaf: profile
532
+ leaf_from: controlint
533
+ name: Battery type
534
+ min: 0
535
+ max: 3
536
+ wireable: false
238
537
  soil:
239
538
  name: Soil
240
539
  topics:
241
540
  - leaf: soil
541
+ tank:
542
+ name: Water Tank
543
+ topics:
544
+ - leaf: tank
545
+ soilmodbus:
546
+ name: "Soil Probe"
547
+ topics:
548
+ # Reuses the shared humidity and temperature definitions - same ranges, logging and
549
+ # duplicate rules - overriding only what soil makes different from air.
550
+ - leaf: humidity
551
+ name: "Soil Moisture"
552
+ color: brown
553
+ units: "%" # Volumetric water content, not the relative humidity the shared leaf means
554
+ - leaf: temperature
555
+ name: "Soil Temperature"
556
+ color: brown
242
557
  ultrasonic:
243
558
  name: "Ultrasonic Distance"
244
559
  topics:
245
560
  - leaf: ultrasonic
561
+ # The irrigation valves - Actuator_Digital instances, so the same shape as `relay`. A node with
562
+ # several publishes valve1, valve2... which the client resolves back to this entry.
563
+ # A switched USB supply - an Actuator_Digital, so the same shape as `relay`. On the FF board this
564
+ # shares a pin with the third irrigation valve; a node has one or the other.
565
+ usb:
566
+ name: USB Supply
567
+ topics:
568
+ - leaf: on
569
+ valve:
570
+ name: Valve
571
+ topics:
572
+ - leaf: on