frugal-iot-server 0.3.7 → 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 +398 -0
- package/README.md +94 -19
- package/config.d/email.yaml +23 -0
- package/config.d/schema/devices.yaml +61 -0
- package/config.d/schema/modules.yaml +337 -39
- package/config.d/schema/topics.yaml +156 -52
- package/extras/mosquitto-bridge.conf.example +130 -0
- package/frugal-iot-server.js +190 -10
- package/lib/housekeeping.js +10 -4
- package/lib/mailer.js +43 -0
- package/lib/resetcode.js +103 -0
- package/package.json +13 -5
- package/public/index.html +16 -0
- package/public/service-worker.js +29 -29
- package/scripts/addbridge-pi.zsh +194 -0
- package/scripts/addbridge-prod.zsh +221 -0
- package/scripts/check-published-files.js +0 -0
- package/scripts/check-schema.js +126 -15
- package/scripts/clearretained.js +185 -0
- package/scripts/copy-schema-to-examples.zsh +9 -5
- package/scripts/diagnostic.zsh +47 -0
- package/scripts/init.zsh +1 -1
- package/scripts/install-pi.sh +646 -0
- package/scripts/not-published.txt +27 -0
- package/scripts/prerelease.zsh +91 -17
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
# name Capitalized English (and add translation below in 'languages')
|
|
10
10
|
# max For gauges, slider
|
|
11
11
|
# min For gauges, slider
|
|
12
|
+
# width Total characters of the rendered number, including any sign and the decimal point and
|
|
13
|
+
# excluding units - the same meaning the node gives it. Decimals are derived, not declared:
|
|
14
|
+
# intWidth = max(len(int(min)), len(int(max))) including a '-', then decimals = width-intWidth-1.
|
|
15
|
+
# Deriving from min/max rather than from the value keeps the decimal count steady as the value
|
|
16
|
+
# moves. Only float and exponential topics need it; an int has no decimals to decide.
|
|
12
17
|
# color can be a name or a #RRGGBB
|
|
13
18
|
# display One of bar,gauge,text,slider,inputbox
|
|
14
19
|
# slot if this topic fits into a specific slot in the enclosing module (currently just frugal_iot module)
|
|
@@ -21,7 +26,8 @@
|
|
|
21
26
|
# no setting at all, any float, int or bool with "rw: r" is recorded, which is easy to be
|
|
22
27
|
# surprised by. scripts/check-schema.js warns about a topic that does not say.
|
|
23
28
|
# duplicates when to bother recording a reading: significantvalue is how much it has to have moved
|
|
24
|
-
# since the last one recorded
|
|
29
|
+
# since the last one recorded - either an absolute amount e.g. 0.5, or as a percentage of the last
|
|
30
|
+
# reading e.g. "2%" - significantdate how long (in milliseconds) since that one, and a
|
|
25
31
|
# reading that meets neither is dropped. Every topic with "log: true" wants a rule here - without
|
|
26
32
|
# one, every reading is written to the SD card as it arrives, which wears the card out.
|
|
27
33
|
# Note battery gets special cased
|
|
@@ -30,10 +36,12 @@ altitude:
|
|
|
30
36
|
leaf: altitude
|
|
31
37
|
name: Altitude
|
|
32
38
|
type: float
|
|
39
|
+
units: m
|
|
33
40
|
display: text
|
|
34
41
|
min: -500
|
|
35
42
|
max: 9000
|
|
36
|
-
|
|
43
|
+
width: 6
|
|
44
|
+
color: "#000000"
|
|
37
45
|
log: true
|
|
38
46
|
duplicates:
|
|
39
47
|
significantdate: 900000
|
|
@@ -59,7 +67,7 @@ aqi:
|
|
|
59
67
|
display: bar
|
|
60
68
|
min: 0
|
|
61
69
|
max: 5
|
|
62
|
-
color:
|
|
70
|
+
color: "#800080"
|
|
63
71
|
rw: r
|
|
64
72
|
graphable: true
|
|
65
73
|
log: true
|
|
@@ -73,7 +81,7 @@ aqi500:
|
|
|
73
81
|
display: bar
|
|
74
82
|
min: 0
|
|
75
83
|
max: 500
|
|
76
|
-
color:
|
|
84
|
+
color: "#a52a2a"
|
|
77
85
|
rw: r
|
|
78
86
|
graphable: true
|
|
79
87
|
log: true
|
|
@@ -87,7 +95,7 @@ battery:
|
|
|
87
95
|
display: text
|
|
88
96
|
min: 3000
|
|
89
97
|
max: 5000
|
|
90
|
-
color:
|
|
98
|
+
color: "#008000"
|
|
91
99
|
rw: r
|
|
92
100
|
graphable: true
|
|
93
101
|
log: true
|
|
@@ -111,7 +119,8 @@ bus:
|
|
|
111
119
|
display: text
|
|
112
120
|
min: 0
|
|
113
121
|
max: 32
|
|
114
|
-
|
|
122
|
+
width: 5
|
|
123
|
+
color: "#008000"
|
|
115
124
|
rw: r
|
|
116
125
|
log: true
|
|
117
126
|
units: V
|
|
@@ -125,7 +134,7 @@ button:
|
|
|
125
134
|
type: bool
|
|
126
135
|
log: true
|
|
127
136
|
display: toggle
|
|
128
|
-
color:
|
|
137
|
+
color: "#000000"
|
|
129
138
|
rw: r
|
|
130
139
|
# A press changes the value, so it is still recorded - this only drops the repeats in between
|
|
131
140
|
duplicates:
|
|
@@ -142,10 +151,11 @@ controlfloat:
|
|
|
142
151
|
#[leaf, name] should be overridden
|
|
143
152
|
min: 0
|
|
144
153
|
max: 100
|
|
154
|
+
width: 5
|
|
145
155
|
type: float
|
|
146
156
|
log: false
|
|
147
157
|
display: text
|
|
148
|
-
color:
|
|
158
|
+
color: "#000000"
|
|
149
159
|
wireable: true
|
|
150
160
|
rw: w
|
|
151
161
|
retain: true
|
|
@@ -156,7 +166,7 @@ controlint:
|
|
|
156
166
|
type: int
|
|
157
167
|
log: false
|
|
158
168
|
display: text
|
|
159
|
-
color:
|
|
169
|
+
color: "#000000"
|
|
160
170
|
wireable: true
|
|
161
171
|
rw: w
|
|
162
172
|
retain: true
|
|
@@ -167,7 +177,7 @@ controltext:
|
|
|
167
177
|
type: text
|
|
168
178
|
log: false
|
|
169
179
|
display: text
|
|
170
|
-
color:
|
|
180
|
+
color: "#000000"
|
|
171
181
|
wireable: true
|
|
172
182
|
rw: w
|
|
173
183
|
retain: true
|
|
@@ -176,7 +186,7 @@ controlintoggle:
|
|
|
176
186
|
type: bool
|
|
177
187
|
log: false
|
|
178
188
|
display: toggle
|
|
179
|
-
color:
|
|
189
|
+
color: "#000000"
|
|
180
190
|
rw: w
|
|
181
191
|
wireable: false
|
|
182
192
|
controlouttoggle:
|
|
@@ -184,7 +194,7 @@ controlouttoggle:
|
|
|
184
194
|
type: bool
|
|
185
195
|
log: true
|
|
186
196
|
display: toggle
|
|
187
|
-
color:
|
|
197
|
+
color: "#000000"
|
|
188
198
|
rw: r
|
|
189
199
|
wireable: true
|
|
190
200
|
# Read-only bool, so logged by default - match the "out" and "on" topics it stands in for
|
|
@@ -198,7 +208,8 @@ course:
|
|
|
198
208
|
display: text
|
|
199
209
|
min: 0
|
|
200
210
|
max: 360
|
|
201
|
-
|
|
211
|
+
width: 5
|
|
212
|
+
color: "#000000"
|
|
202
213
|
log: true
|
|
203
214
|
duplicates:
|
|
204
215
|
significantdate: 900000
|
|
@@ -213,7 +224,8 @@ current:
|
|
|
213
224
|
display: text
|
|
214
225
|
min: -3200
|
|
215
226
|
max: 3200
|
|
216
|
-
|
|
227
|
+
width: 7
|
|
228
|
+
color: "#ff0000"
|
|
217
229
|
rw: r
|
|
218
230
|
log: true
|
|
219
231
|
units: mA
|
|
@@ -237,7 +249,8 @@ do:
|
|
|
237
249
|
display: bar
|
|
238
250
|
min: 0
|
|
239
251
|
max: 20
|
|
240
|
-
|
|
252
|
+
width: 5
|
|
253
|
+
color: "#0000ff"
|
|
241
254
|
rw: r
|
|
242
255
|
log: true
|
|
243
256
|
units: mg/L
|
|
@@ -252,7 +265,7 @@ eco2:
|
|
|
252
265
|
display: bar
|
|
253
266
|
min: 300
|
|
254
267
|
max: 900
|
|
255
|
-
color:
|
|
268
|
+
color: "#a52a2a"
|
|
256
269
|
log: true
|
|
257
270
|
units: ppm
|
|
258
271
|
duplicates:
|
|
@@ -267,7 +280,8 @@ gas:
|
|
|
267
280
|
display: text
|
|
268
281
|
min: 0
|
|
269
282
|
max: 500
|
|
270
|
-
|
|
283
|
+
width: 5
|
|
284
|
+
color: "#008000"
|
|
271
285
|
rw: r
|
|
272
286
|
log: true
|
|
273
287
|
units: kOhm
|
|
@@ -282,7 +296,8 @@ hdop:
|
|
|
282
296
|
display: text
|
|
283
297
|
min: 0
|
|
284
298
|
max: 50
|
|
285
|
-
|
|
299
|
+
width: 5
|
|
300
|
+
color: "#000000"
|
|
286
301
|
log: false
|
|
287
302
|
duplicates:
|
|
288
303
|
significantdate: 900000
|
|
@@ -296,7 +311,8 @@ humidity:
|
|
|
296
311
|
display: bar
|
|
297
312
|
min: 0
|
|
298
313
|
max: 100
|
|
299
|
-
|
|
314
|
+
width: 5
|
|
315
|
+
color: "#0000ff"
|
|
300
316
|
log: true
|
|
301
317
|
duplicates:
|
|
302
318
|
significantdate: 900000
|
|
@@ -325,7 +341,7 @@ language_code:
|
|
|
325
341
|
type: text
|
|
326
342
|
log: false
|
|
327
343
|
display: text
|
|
328
|
-
color:
|
|
344
|
+
color: "#000000"
|
|
329
345
|
rw: r
|
|
330
346
|
lastseen:
|
|
331
347
|
leaf: lastseen
|
|
@@ -342,7 +358,8 @@ latitude:
|
|
|
342
358
|
display: text
|
|
343
359
|
min: -90
|
|
344
360
|
max: +90
|
|
345
|
-
|
|
361
|
+
width: 9
|
|
362
|
+
color: "#000000"
|
|
346
363
|
log: true
|
|
347
364
|
duplicates:
|
|
348
365
|
significantdate: 900000
|
|
@@ -357,7 +374,8 @@ load:
|
|
|
357
374
|
display: text
|
|
358
375
|
min: 0
|
|
359
376
|
max: 32
|
|
360
|
-
|
|
377
|
+
width: 5
|
|
378
|
+
color: "#008000"
|
|
361
379
|
rw: r
|
|
362
380
|
log: true
|
|
363
381
|
units: V
|
|
@@ -372,7 +390,8 @@ loadcell:
|
|
|
372
390
|
display: text
|
|
373
391
|
min: 0
|
|
374
392
|
max: 65000
|
|
375
|
-
|
|
393
|
+
width: 7
|
|
394
|
+
color: "#b8860b"
|
|
376
395
|
log: true
|
|
377
396
|
duplicates:
|
|
378
397
|
significantdate: 900000
|
|
@@ -387,7 +406,8 @@ longitude:
|
|
|
387
406
|
display: text
|
|
388
407
|
min: -180
|
|
389
408
|
max: +180
|
|
390
|
-
|
|
409
|
+
width: 10
|
|
410
|
+
color: "#000000"
|
|
391
411
|
log: true
|
|
392
412
|
duplicates:
|
|
393
413
|
significantdate: 900000
|
|
@@ -402,12 +422,13 @@ lux:
|
|
|
402
422
|
display: bar
|
|
403
423
|
min: 0
|
|
404
424
|
max: 65000
|
|
405
|
-
|
|
425
|
+
width: 5
|
|
426
|
+
color: "#b8860b"
|
|
406
427
|
log: true
|
|
407
428
|
rw: r
|
|
408
429
|
duplicates:
|
|
409
430
|
significantdate: 900000
|
|
410
|
-
significantvalue:
|
|
431
|
+
significantvalue: 5%
|
|
411
432
|
graphable: true
|
|
412
433
|
units: lx
|
|
413
434
|
manual:
|
|
@@ -415,7 +436,7 @@ manual:
|
|
|
415
436
|
name: Manual
|
|
416
437
|
type: bool
|
|
417
438
|
display: toggle
|
|
418
|
-
color:
|
|
439
|
+
color: "#000000"
|
|
419
440
|
rw: r
|
|
420
441
|
log: true
|
|
421
442
|
graphable: true
|
|
@@ -431,7 +452,7 @@ message:
|
|
|
431
452
|
type: text
|
|
432
453
|
log: false
|
|
433
454
|
display: text
|
|
434
|
-
color:
|
|
455
|
+
color: "#000000"
|
|
435
456
|
wireable: true
|
|
436
457
|
rw: w
|
|
437
458
|
retain: true
|
|
@@ -442,7 +463,8 @@ mm:
|
|
|
442
463
|
display: text
|
|
443
464
|
min: 0
|
|
444
465
|
max: 500
|
|
445
|
-
|
|
466
|
+
width: 5
|
|
467
|
+
color: "#0000ff"
|
|
446
468
|
rw: r
|
|
447
469
|
log: true
|
|
448
470
|
duplicates:
|
|
@@ -464,7 +486,7 @@ on:
|
|
|
464
486
|
name: On
|
|
465
487
|
type: bool
|
|
466
488
|
display: toggle
|
|
467
|
-
color:
|
|
489
|
+
color: "#000000"
|
|
468
490
|
rw: w
|
|
469
491
|
log: true
|
|
470
492
|
duplicates:
|
|
@@ -476,7 +498,7 @@ out:
|
|
|
476
498
|
name: Out
|
|
477
499
|
type: bool
|
|
478
500
|
display: toggle
|
|
479
|
-
color:
|
|
501
|
+
color: "#000000"
|
|
480
502
|
rw: r
|
|
481
503
|
log: true
|
|
482
504
|
wireable: true
|
|
@@ -484,13 +506,33 @@ out:
|
|
|
484
506
|
duplicates:
|
|
485
507
|
significantdate: 900000
|
|
486
508
|
significantvalue: 1
|
|
509
|
+
percent:
|
|
510
|
+
# A 0-100% figure that is worth recording and graphing - state of charge, battery health. Unlike
|
|
511
|
+
# controlfloat it is read-only and logged, so it needs its own duplicate rule; [name] and the
|
|
512
|
+
# duplicate thresholds should be overridden per module.
|
|
513
|
+
leaf: percent
|
|
514
|
+
name: Percent
|
|
515
|
+
type: float
|
|
516
|
+
display: bar
|
|
517
|
+
min: 0
|
|
518
|
+
max: 100
|
|
519
|
+
width: 3
|
|
520
|
+
color: "#008000"
|
|
521
|
+
rw: r
|
|
522
|
+
wireable: false
|
|
523
|
+
log: true
|
|
524
|
+
duplicates:
|
|
525
|
+
significantdate: 900000
|
|
526
|
+
significantvalue: 1
|
|
527
|
+
graphable: true
|
|
528
|
+
units: "%"
|
|
487
529
|
position:
|
|
488
530
|
leaf: position
|
|
489
531
|
name: Position
|
|
490
532
|
type: text
|
|
491
533
|
log: false
|
|
492
534
|
display: text
|
|
493
|
-
color:
|
|
535
|
+
color: "#000000"
|
|
494
536
|
rw: r
|
|
495
537
|
power:
|
|
496
538
|
leaf: power
|
|
@@ -499,7 +541,8 @@ power:
|
|
|
499
541
|
display: text
|
|
500
542
|
min: 0
|
|
501
543
|
max: 100000
|
|
502
|
-
|
|
544
|
+
width: 8
|
|
545
|
+
color: "#ffa500"
|
|
503
546
|
rw: r
|
|
504
547
|
log: true
|
|
505
548
|
units: mW
|
|
@@ -512,9 +555,11 @@ pressure:
|
|
|
512
555
|
name: Pressure
|
|
513
556
|
type: float
|
|
514
557
|
display: bar
|
|
515
|
-
min:
|
|
516
|
-
max:
|
|
517
|
-
|
|
558
|
+
min: 300
|
|
559
|
+
max: 1100
|
|
560
|
+
width: 6
|
|
561
|
+
units: hPa
|
|
562
|
+
color: "#0000ff"
|
|
518
563
|
rw: r
|
|
519
564
|
log: true
|
|
520
565
|
duplicates:
|
|
@@ -528,7 +573,8 @@ rain:
|
|
|
528
573
|
display: text
|
|
529
574
|
min: 0
|
|
530
575
|
max: 500
|
|
531
|
-
|
|
576
|
+
width: 5
|
|
577
|
+
color: "#0000ff"
|
|
532
578
|
rw: r
|
|
533
579
|
log: true
|
|
534
580
|
duplicates:
|
|
@@ -543,14 +589,15 @@ satellites:
|
|
|
543
589
|
display: text
|
|
544
590
|
min: 0
|
|
545
591
|
max: 32
|
|
546
|
-
|
|
592
|
+
width: 2
|
|
593
|
+
color: "#000000"
|
|
547
594
|
log: false
|
|
548
595
|
duplicates:
|
|
549
596
|
significantdate: 900000
|
|
550
597
|
significantvalue: 1
|
|
551
598
|
rw: r
|
|
552
599
|
graphable: false
|
|
553
|
-
units:
|
|
600
|
+
units: count
|
|
554
601
|
select:
|
|
555
602
|
leaf: select
|
|
556
603
|
name: Select
|
|
@@ -558,7 +605,7 @@ select:
|
|
|
558
605
|
log: false
|
|
559
606
|
min: 0
|
|
560
607
|
display: text
|
|
561
|
-
color:
|
|
608
|
+
color: "#000000"
|
|
562
609
|
wireable: false
|
|
563
610
|
rw: w
|
|
564
611
|
retain: true
|
|
@@ -569,7 +616,8 @@ shunt:
|
|
|
569
616
|
display: text
|
|
570
617
|
min: -320
|
|
571
618
|
max: 320
|
|
572
|
-
|
|
619
|
+
width: 6
|
|
620
|
+
color: "#0000ff"
|
|
573
621
|
rw: r
|
|
574
622
|
log: true
|
|
575
623
|
units: mV
|
|
@@ -584,7 +632,8 @@ speed:
|
|
|
584
632
|
display: text
|
|
585
633
|
min: 0
|
|
586
634
|
max: 999
|
|
587
|
-
|
|
635
|
+
width: 5
|
|
636
|
+
color: "#000000"
|
|
588
637
|
log: true
|
|
589
638
|
duplicates:
|
|
590
639
|
significantdate: 900000
|
|
@@ -599,7 +648,7 @@ soil:
|
|
|
599
648
|
display: bar
|
|
600
649
|
min: 0
|
|
601
650
|
max: 100
|
|
602
|
-
color:
|
|
651
|
+
color: "#a52a2a"
|
|
603
652
|
rw: r
|
|
604
653
|
log: true
|
|
605
654
|
duplicates:
|
|
@@ -607,7 +656,23 @@ soil:
|
|
|
607
656
|
significantvalue: 1
|
|
608
657
|
graphable: true
|
|
609
658
|
calibrate: true
|
|
610
|
-
units: "%
|
|
659
|
+
units: "%"
|
|
660
|
+
tank:
|
|
661
|
+
leaf: tank
|
|
662
|
+
name: Water Tank
|
|
663
|
+
type: float
|
|
664
|
+
display: bar
|
|
665
|
+
min: 0
|
|
666
|
+
max: 100
|
|
667
|
+
width: 5
|
|
668
|
+
color: "#0000ff"
|
|
669
|
+
rw: r
|
|
670
|
+
log: true
|
|
671
|
+
duplicates:
|
|
672
|
+
significantdate: 900000
|
|
673
|
+
significantvalue: 1
|
|
674
|
+
graphable: true
|
|
675
|
+
units: "%"
|
|
611
676
|
temperature:
|
|
612
677
|
leaf: temperature
|
|
613
678
|
name: Temperature
|
|
@@ -616,7 +681,8 @@ temperature:
|
|
|
616
681
|
rw: r
|
|
617
682
|
min: 0
|
|
618
683
|
max: 50
|
|
619
|
-
|
|
684
|
+
width: 4
|
|
685
|
+
color: "#ff0000"
|
|
620
686
|
wireable: false
|
|
621
687
|
log: true
|
|
622
688
|
units: Cel
|
|
@@ -629,10 +695,11 @@ timeoff:
|
|
|
629
695
|
name: Time Off (s)
|
|
630
696
|
min: 0
|
|
631
697
|
max: 3600
|
|
698
|
+
width: 4
|
|
632
699
|
type: float
|
|
633
700
|
log: false
|
|
634
701
|
display: text
|
|
635
|
-
color:
|
|
702
|
+
color: "#000000"
|
|
636
703
|
rw: w
|
|
637
704
|
wireable: true
|
|
638
705
|
units: s
|
|
@@ -641,10 +708,11 @@ timeon:
|
|
|
641
708
|
name: Time On (s)
|
|
642
709
|
min: 0
|
|
643
710
|
max: 3600
|
|
711
|
+
width: 4
|
|
644
712
|
type: float
|
|
645
713
|
log: false
|
|
646
714
|
display: text
|
|
647
|
-
color:
|
|
715
|
+
color: "#000000"
|
|
648
716
|
rw: w
|
|
649
717
|
wireable: true
|
|
650
718
|
units: s
|
|
@@ -655,7 +723,7 @@ tvoc:
|
|
|
655
723
|
display: bar
|
|
656
724
|
min: 0
|
|
657
725
|
max: 99
|
|
658
|
-
color:
|
|
726
|
+
color: "#008000"
|
|
659
727
|
rw: r
|
|
660
728
|
log: true
|
|
661
729
|
units: ppb
|
|
@@ -670,7 +738,8 @@ ultrasonic:
|
|
|
670
738
|
display: bar
|
|
671
739
|
min: 0
|
|
672
740
|
max: 7500
|
|
673
|
-
|
|
741
|
+
width: 4
|
|
742
|
+
color: "#0000ff"
|
|
674
743
|
rw: r
|
|
675
744
|
log: true
|
|
676
745
|
units: mm
|
|
@@ -685,8 +754,43 @@ utc_time:
|
|
|
685
754
|
type: text
|
|
686
755
|
log: false
|
|
687
756
|
display: text
|
|
688
|
-
color:
|
|
757
|
+
color: "#000000"
|
|
758
|
+
rw: r
|
|
759
|
+
voltage:
|
|
760
|
+
# A DC voltage read through a resistor divider - see Sensor_Voltage in the library. Millivolts,
|
|
761
|
+
# like `battery`, but without that topic's single-lithium-cell range or its special-casing in
|
|
762
|
+
# the UX. [name, min, max] should be overridden per module.
|
|
763
|
+
leaf: voltage
|
|
764
|
+
name: Voltage
|
|
765
|
+
type: int
|
|
766
|
+
display: text
|
|
767
|
+
min: 0
|
|
768
|
+
max: 30000
|
|
769
|
+
color: "#800080"
|
|
689
770
|
rw: r
|
|
771
|
+
graphable: true
|
|
772
|
+
log: true
|
|
773
|
+
units: mV
|
|
774
|
+
duplicates:
|
|
775
|
+
significantdate: 900000
|
|
776
|
+
significantvalue: 100
|
|
777
|
+
volts:
|
|
778
|
+
leaf: volts
|
|
779
|
+
name: Volts
|
|
780
|
+
type: float
|
|
781
|
+
display: slider
|
|
782
|
+
rw: w
|
|
783
|
+
min: 0
|
|
784
|
+
max: 3.3
|
|
785
|
+
width: 4
|
|
786
|
+
color: "#800080"
|
|
787
|
+
units: V
|
|
788
|
+
wireable: true
|
|
789
|
+
log: true
|
|
790
|
+
duplicates:
|
|
791
|
+
significantdate: 900000
|
|
792
|
+
significantvalue: 0.05
|
|
793
|
+
graphable: true
|
|
690
794
|
wifibars:
|
|
691
795
|
leaf: wifibars
|
|
692
796
|
name: WiFi
|
|
@@ -695,7 +799,7 @@ wifibars:
|
|
|
695
799
|
display: text
|
|
696
800
|
min: 0
|
|
697
801
|
max: 4
|
|
698
|
-
color:
|
|
802
|
+
color: "#0000ff"
|
|
699
803
|
rw: r
|
|
700
804
|
# Logged, because an int that is read-only is logged unless told otherwise. Only 5 values, so
|
|
701
805
|
# any change is worth recording and nothing else is
|
|
@@ -708,5 +812,5 @@ wifissid:
|
|
|
708
812
|
type: text
|
|
709
813
|
log: false
|
|
710
814
|
display: text
|
|
711
|
-
color:
|
|
815
|
+
color: "#0000ff"
|
|
712
816
|
rw: r
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Bridging this Pi's broker to a production Frugal IoT server
|
|
2
|
+
#
|
|
3
|
+
# Optional. Without this file the Pi is self-contained: nodes publish to the broker here, the
|
|
4
|
+
# logger records the readings here, and the dashboard here shows them. Adding it also relays
|
|
5
|
+
# everything to a production server, so the same nodes appear on a dashboard elsewhere and can be
|
|
6
|
+
# controlled from it, while the Pi carries on working on its own whenever the link is down.
|
|
7
|
+
#
|
|
8
|
+
# This is a Mosquitto "bridge" - the broker's own feature for connecting to another broker. The
|
|
9
|
+
# server, the logger and the nodes know nothing about it and need no configuration change.
|
|
10
|
+
#
|
|
11
|
+
# To use it:
|
|
12
|
+
# sudo cp extras/mosquitto-bridge.conf.example /etc/mosquitto/conf.d/frugal-iot-bridge.conf
|
|
13
|
+
# sudo nano /etc/mosquitto/conf.d/frugal-iot-bridge.conf # replace every <...> below
|
|
14
|
+
# sudo systemctl restart mosquitto
|
|
15
|
+
#
|
|
16
|
+
# It has to be a restart, not a reload: Mosquitto does not pick up bridges on a reload signal.
|
|
17
|
+
# That briefly disconnects every node, which they recover from on their own.
|
|
18
|
+
#
|
|
19
|
+
# The file goes in /etc/mosquitto/conf.d/ rather than in this installation, because it holds a
|
|
20
|
+
# password for the production broker. Everything under config.d/ here is served to any logged-in
|
|
21
|
+
# browser by /config.json, so a credential put there would not stay private.
|
|
22
|
+
|
|
23
|
+
# ============ The connection ============
|
|
24
|
+
|
|
25
|
+
# Names the bridge. Anything, but it appears in the log, so make it recognisable.
|
|
26
|
+
connection to-prod
|
|
27
|
+
|
|
28
|
+
# The production broker's plain-MQTT-over-TLS address. Not the wss:// URL the browsers and the
|
|
29
|
+
# server use - a Mosquitto bridge speaks MQTT or MQTT-over-TLS and cannot use WebSockets, so
|
|
30
|
+
# production needs a listener on 8883 for this. Port 1883 would work on a trusted LAN, but sends
|
|
31
|
+
# the password below in clear, so over the internet use 8883 and keep the TLS lines further down.
|
|
32
|
+
address <prod-host>:8883
|
|
33
|
+
|
|
34
|
+
# The account this Pi uses on the production broker. Give each Pi its own, rather than sharing the
|
|
35
|
+
# organization's account: the organization password is handed to every browser that logs in, so it
|
|
36
|
+
# is not a secret, and a per-Pi account can be restricted to just this site's topics and revoked
|
|
37
|
+
# on its own.
|
|
38
|
+
remote_username <bridge-account>
|
|
39
|
+
remote_password <bridge-password>
|
|
40
|
+
|
|
41
|
+
# The client id this Pi presents to production, and the name production uses when it reports the
|
|
42
|
+
# state of this bridge (see "notifications" below). One per Pi, or two Pis will disconnect each
|
|
43
|
+
# other in a loop as each takes over the other's session.
|
|
44
|
+
remote_clientid <bridge-account>
|
|
45
|
+
|
|
46
|
+
# Verify production's certificate against the system CA store, which is what a Let's Encrypt
|
|
47
|
+
# certificate on production needs - no certificate has to be copied onto this Pi. Delete both
|
|
48
|
+
# lines, and use port 1883 above, only on a network you trust end to end.
|
|
49
|
+
bridge_cafile /etc/ssl/certs/ca-certificates.crt
|
|
50
|
+
bridge_insecure false
|
|
51
|
+
|
|
52
|
+
# How long to wait before retrying, in seconds, doubling from the first number up to the second.
|
|
53
|
+
# A Pi on a weak or intermittent link keeps retrying for as long as it takes; the cap stops a
|
|
54
|
+
# flapping connection from hammering production.
|
|
55
|
+
restart_timeout 5 60
|
|
56
|
+
|
|
57
|
+
# Keep production's copy of our subscriptions across a dropped connection. This is the default,
|
|
58
|
+
# and it matters: with "true" instead, Mosquitto re-subscribes on every reconnect and production
|
|
59
|
+
# re-sends every retained message each time, which on a flaky link means a burst of duplicated
|
|
60
|
+
# readings after every blip. Nodes publish nearly everything retained, so that burst is large.
|
|
61
|
+
cleansession false
|
|
62
|
+
|
|
63
|
+
# Publish a retained "1" or "0" to $SYS/broker/connection/<remote_clientid>/state on both brokers
|
|
64
|
+
# whenever the link comes up or goes down. This is how "npx --no frugal-iot-diagnostic" reports
|
|
65
|
+
# whether the bridge is connected, and it also lets production see which sites are reachable.
|
|
66
|
+
# The default is true; it is written out here because it is useful rather than incidental.
|
|
67
|
+
notifications true
|
|
68
|
+
|
|
69
|
+
# Uncomment if production refuses the bridge's connection or logs a denied publish to $SYS. Once
|
|
70
|
+
# production has an acl_file, writing to $SYS may not be permitted, and this stops trying: the
|
|
71
|
+
# state is then published only to the broker here, which is all the diagnostic script reads. What
|
|
72
|
+
# is lost is production's view of whether this site is reachable.
|
|
73
|
+
#notifications_local_only true
|
|
74
|
+
|
|
75
|
+
# Not set, and worth knowing why: local_username / local_password. The broker here requires
|
|
76
|
+
# authentication, but a bridge's local side is internal to the broker and does not go through it.
|
|
77
|
+
# Verified on mosquitto 2.0.21 - an anonymous publish is refused while the bridge still forwards.
|
|
78
|
+
|
|
79
|
+
# ============ What gets relayed ============
|
|
80
|
+
#
|
|
81
|
+
# Replace <org> in all four lines with the organization id - the first element of every topic, and
|
|
82
|
+
# the name of the file in config.d/organizations/. One set of four lines per organization on this
|
|
83
|
+
# Pi. To relay only some projects, replace "<org>/" with "<org>/<project>/" and add "+/" where a
|
|
84
|
+
# level is now missing, or repeat the block per project.
|
|
85
|
+
#
|
|
86
|
+
# Frugal IoT topics come in five shapes, and each line below picks out one or two of them. "+"
|
|
87
|
+
# matches exactly one level, so counting levels is what separates them:
|
|
88
|
+
#
|
|
89
|
+
# <org>/<project> the "quick discover" announcement
|
|
90
|
+
# <org>/<project>/<node>/<module>/<field> a reading
|
|
91
|
+
# <org>/<project>/<node>/<module>/<field>/<parameter> a reading's min, max, colour, wiring
|
|
92
|
+
# <org>/<project>/<node>/set/<module>/<field> a control
|
|
93
|
+
# <org>/<project>/<node>/set/<module>/<field>/<parameter>
|
|
94
|
+
#
|
|
95
|
+
# Readings, at five levels. These are the only topics the logger writes to disk, so this is the
|
|
96
|
+
# one line where a topic must not be matched twice - each extra copy would be another row in the
|
|
97
|
+
# CSV files at the far end.
|
|
98
|
+
#
|
|
99
|
+
# The "0" is the QoS, and it is doing real work. At 0, anything published while production is
|
|
100
|
+
# unreachable is simply dropped: production's history has a gap for the outage and this Pi's is
|
|
101
|
+
# complete. At 1 the broker would instead queue it all up and deliver it on reconnect, where
|
|
102
|
+
# production stamps each reading with the time it arrived - so an outage would come back as a
|
|
103
|
+
# whole day's readings all claiming to have happened at the moment the link returned, which is
|
|
104
|
+
# worse than a gap because it looks like real data. Leave this at 0.
|
|
105
|
+
topic <org>/+/+/+/+ out 0
|
|
106
|
+
|
|
107
|
+
# The quick discover announcement, so production learns which nodes live here. Sent periodically
|
|
108
|
+
# and not retained, so nothing accumulates while the link is down.
|
|
109
|
+
topic <org>/+ out 0
|
|
110
|
+
|
|
111
|
+
# Parameters - the min, max, colour and wiring a node announces once at startup. The dashboard
|
|
112
|
+
# needs them to draw a node properly, and the logger never records them.
|
|
113
|
+
topic <org>/+/+/+/+/+ out 0
|
|
114
|
+
|
|
115
|
+
# Controls, in both directions and at QoS 1. Both directions, because a control can be set from
|
|
116
|
+
# either dashboard and both brokers need to know. QoS 1 because here queueing is exactly what is
|
|
117
|
+
# wanted: a control set on production while this Pi is offline is held and delivered when it comes
|
|
118
|
+
# back, which is the same reason nodes publish these retained.
|
|
119
|
+
#
|
|
120
|
+
# At six levels this overlaps the parameter line above, so some controls reach production twice.
|
|
121
|
+
# That is deliberate - it is the harmless place to put the overlap, since a repeated control
|
|
122
|
+
# carries the same value and the logger discards anything with "set" in it. There is no way to
|
|
123
|
+
# write "six levels but not a control", as MQTT patterns cannot exclude.
|
|
124
|
+
topic <org>/+/+/set/# both 1
|
|
125
|
+
|
|
126
|
+
# Loop protection is Mosquitto's "try_private", on by default, which tells production that this is
|
|
127
|
+
# a bridge and not an ordinary client so that it never echoes our own messages back at us. Both
|
|
128
|
+
# ends must be Mosquitto for that to hold - it was measured working between 2.0.21 and itself.
|
|
129
|
+
# TODO revisit if production ever moves to a different broker, or if a third broker is ever
|
|
130
|
+
# bridged into the same topics, as neither case is covered by that protection.
|