Repository navigation
Expand file tree
/
Copy path03_software_req.sdoc
More file actions
3059 lines (2595 loc) · 131 KB
/
Copy path03_software_req.sdoc
File metadata and controls
3059 lines (2595 loc) · 131 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[DOCUMENT]
TITLE: Safe Kiln Controller, Software Requirements
UID: SAFEKILN-SWR
VERSION: 0.1 (draft)
DATE: 2026-10-08
OPTIONS:
MARKUP: Markdown
VIEW_STYLE: Table
NODE_IN_TOC: True
METADATA:
SPDX-FileCopyrightText: 2026 Bitcrush Testing
SPDX-License-Identifier: GPL-3.0-or-later
Status: For review
Project: Safe Kiln Controller, PID kiln controller
[GRAMMAR]
ELEMENTS:
- TAG: TEXT
FIELDS:
- TITLE: STATEMENT
TYPE: String
REQUIRED: True
- TAG: SECTION
PROPERTIES:
IS_COMPOSITE: True
FIELDS:
- TITLE: UID
TYPE: String
REQUIRED: False
- TITLE: TITLE
TYPE: String
REQUIRED: True
- TAG: REQUIREMENT
FIELDS:
- TITLE: UID
TYPE: String
REQUIRED: True
- TITLE: STATEMENT
TYPE: String
REQUIRED: True
- TITLE: RATIONALE
TYPE: String
REQUIRED: False
- TITLE: PRIORITY
TYPE: SingleChoice(M, S, C, W)
REQUIRED: False
- TITLE: VERIFICATION
TYPE: MultipleChoice(T, A, I, D)
REQUIRED: False
- TITLE: STATUS
TYPE: SingleChoice(Active, Withdrawn, Superseded, Reversed, Resolved)
REQUIRED: False
RELATIONS:
- TYPE: Parent
- TAG: CONSTRAINT
FIELDS:
- TITLE: UID
TYPE: String
REQUIRED: True
- TITLE: STATEMENT
TYPE: String
REQUIRED: True
- TITLE: STATUS
TYPE: SingleChoice(Active, Withdrawn, Superseded, Reversed, Resolved)
REQUIRED: False
- TAG: ASSUMPTION
FIELDS:
- TITLE: UID
TYPE: String
REQUIRED: True
- TITLE: STATEMENT
TYPE: String
REQUIRED: True
- TITLE: STATUS
TYPE: SingleChoice(Active, Withdrawn, Superseded, Reversed, Resolved)
REQUIRED: False
- TAG: QUESTION
FIELDS:
- TITLE: UID
TYPE: String
REQUIRED: True
- TITLE: STATEMENT
TYPE: String
REQUIRED: True
- TITLE: STATUS
TYPE: SingleChoice(Active, Withdrawn, Superseded, Reversed, Resolved)
REQUIRED: False
[TEXT]
STATEMENT: >>>
Level 3 of the V-model (see [`v-model-process.md`](v-model-process.md)): what the
**software** must do, as allocated from the system requirements of
[`02_system_req.sdoc`](02_system_req.sdoc). Refined by the software architecture
of [`04_software_arch.sdoc`](04_software_arch.sdoc) and verified by integration
tests.
The sub-prefix after `SWR-` is the functional area and is a deliberate deviation
from the flat `SWR-nnn` numbering the process document's examples show. With 169
functional requirements, `SWR-CTL-07` says where it belongs and `SWR-112` does
not, and the areas were already the document's structure. The process document
records the deviation.
`SWR-SAF-` are the 27 safety requirements that are software behaviour; the four
that hardware discharges are in `02_system_req.sdoc`. `SWR-NFR-` are the
non-functional requirements, all of which turned out to be software-level.
`SWR-TST-` are the testability requirements, which constrain the software so that
it can be verified at all.
<<<
[[SECTION]]
UID: SECT-1
TITLE: 1. Introduction
[[SECTION]]
UID: SECT-1-1
TITLE: 1.1 Purpose
[TEXT]
STATEMENT: >>>
This document specifies the requirements for **Safe Kiln Controller**, an open-source
temperature controller for electric ceramic / glass kilns. It is the reference
for implementation, verification and review. The software architecture derived
from this document is [`architecture.md`](architecture.md).
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-1-2
TITLE: 1.2 Scope
[TEXT]
STATEMENT: >>>
Safe Kiln Controller replaces the mechanical or simple on/off controller of an electric
kiln with a closed-loop PID controller that follows a user-defined
**firing curve** (a time/temperature program). The operator interacts with the
device through a small local display and, over WiFi, through a built-in web
interface that also visualises logged temperature data.
In scope:
- Temperature acquisition from a type-K thermocouple in the kiln chamber, plus a
second thermocouple for enclosure/electronics temperature.
- Time-proportional PID control of a solid-state relay switching the heating
elements, with an independent safety contactor.
- Measurement of heater current with a current transformer (Stromwandler), for
direct electrical detection of a failed relay, contactor or heating element.
- Automatic PID tuning against the real kiln.
- Storage and execution of multi-segment firing programs.
- Local display of current and target temperature plus program state.
- A self-hosted web interface for program editing, live monitoring, historical
temperature charts and configuration.
- On-device logging of every firing run without an SD card or external database.
- Safety supervision: thermal runaway, sensor failure, relay failure,
over-temperature.
Out of scope: see §12 ([LINK: SECT-12]).
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-1-3
TITLE: 1.3 Definitions and abbreviations
[TEXT]
STATEMENT: >>>
| Term | Meaning |
|---|---|
| **Firing program** | Ordered list of segments describing a complete firing. Also "curve", "profile", "schedule". |
| **Segment** | One element of a program: ramp to a target temperature at a given rate, then dwell (hold) for a given time. |
| **Setpoint (SP)** | The instantaneous temperature the controller is aiming for. Produced by the setpoint generator from the active program; it is *not* the segment target except at the end of a ramp. |
| **Process value (PV)** | The measured kiln temperature. |
| **Control output (CV)** | PID output, 0–100 % heating duty. |
| **Dwell / soak** | Holding the temperature constant for a defined time. |
| **Ramp rate** | Rate of change of the setpoint, in °C/h. |
| **Hold-back** | Suspension of setpoint advance while PV lags SP beyond a threshold, so a slow kiln cannot silently fall behind its curve. |
| **SSR** | Solid-state relay. Modulates heater power. |
| **Contactor / EMR** | Electromechanical relay or contactor in series with the SSR. Provides a galvanic break independent of the SSR. |
| **TC** | Thermocouple. |
| **CJC** | Cold-junction compensation. |
| **Stromwandler / CT** | Current transformer. A split-core clip-on transformer around one heater conductor giving a galvanically isolated signal proportional to heater current. |
| **Burden** | The resistor across a CT secondary that turns its output current into a voltage. A current-output CT whose burden is removed while primary current flows develops dangerous open-circuit voltages. |
| **RMS** | Root mean square: the heating-equivalent value of an alternating waveform. |
| **Fail-on / fail-off** | A switching device stuck conducting (fail-on) or stuck open (fail-off). A shorted SSR and a welded contactor are both fail-on faults. |
| **Weld discrimination** | Determining whether unexpected current is due to a shorted SSR or a welded contactor, by dropping the contactor and re-measuring. |
| **Time-proportional control** | Converting a 0–100 % duty into on/off intervals within a fixed window, since an SSR cannot be driven at an analogue level. |
| **Relay autotune** | Åström–Hägglund method: force a bounded limit cycle with on/off control, measure its amplitude and period, derive PID gains. |
| **HAL** | Hardware abstraction layer. |
| **HIL** | Hardware in the loop. |
| **SUT** | System under test. |
| **NVS** | ESP-IDF Non-Volatile Storage (key/value store in flash). |
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-1-4
TITLE: 1.4 Requirement conventions
[TEXT]
STATEMENT: >>>
Each requirement has a stable identifier, a **shall** statement, and a
verification method:
| Code | Method | Meaning |
|---|---|---|
| **T** | Test | Automated test (host unit test, target test, or HIL test). |
| **A** | Analysis | Calculation, model, static analysis or code metric. |
| **I** | Inspection | Review of code, schematic or document. |
| **D** | Demonstration | Operating the system and observing behaviour. |
Priority: **M** = mandatory for v1.0, **S** = should have, **C** = could have
(deferred without blocking release).
Identifier prefixes:
| Prefix | Area |
|---|---|
| `ASM` | Assumption |
| `CON` | Constraint |
| `FR-ACQ` | Temperature acquisition |
| `FR-CTL` | Control loop |
| `FR-TUN` | Automatic PID tuning |
| `FR-PRG` | Firing programs |
| `FR-RUN` | Run control and state machine |
| `FR-HMI` | Local display and input |
| `FR-WEB` | Web interface |
| `FR-LOG` | Data logging |
| `FR-CFG` | Configuration |
| `FR-NET` | Connectivity and time |
| `FR-UPD` | Firmware update |
| `SR` | Safety requirement |
| `NFR` | Non-functional requirement |
| `HR` | Hardware interface requirement |
| `TR` | Testability requirement |
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-1-5
TITLE: 1.5 References
[TEXT]
STATEMENT: >>>
| Ref | Document |
|---|---|
| [R1] | [PIDKiln](https://github.com/Saur0o0n/PIDKiln) by Adrian Siemieniak, ESP32 kiln controller, the functional inspiration for this project (GPL-3.0). |
| [R2] | Espressif, *ESP-IDF Programming Guide*, v5.x. |
| [R3] | Analog Devices, *MAX31856 Precision Thermocouple to Digital Converter with Linearization*, datasheet. |
| [R4] | IEC 60584-1, *Thermocouples, Part 1: EMF specifications and tolerances*. |
| [R5] | K. J. Åström, T. Hägglund, *PID Controllers: Theory, Design and Tuning*, 2nd ed., 1995. |
| [R6] | IEC 60519-1, *Safety in installations for electroheating and electromagnetic processing*. |
| [R7] | GNU General Public License version 3, [`../LICENSE`](../LICENSE). |
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-1-6
TITLE: 1.6 Relationship to PIDKiln
[TEXT]
STATEMENT: >>>
PIDKiln [R1] demonstrates that a ~40 USD ESP32 board can run a real kiln, and
this project adopts its proven ideas: a segment-based program model
(`target / ramp / dwell`), dual display and web control, on-device storage with
no external services, a redundant SSR + contactor output stage, and safety
supervision covering runaway, probe failure, SSR failure and insulation
degradation.
Safe Kiln Controller deliberately diverges in the following respects, and these
divergences drive many requirements below:
| Aspect | PIDKiln | Safe Kiln Controller | Driver |
|---|---|---|---|
| Framework | Arduino-ESP32 | ESP-IDF v5.x ([LINK: UR-CON-01]) | Explicit requirement; better test tooling, partition/OTA control, watchdogs |
| MCU | ESP32-WROVER | ESP32-S3 ([LINK: SYS-HW-01]) | Explicit requirement |
| TC front-end | MAX31855 (K only, ≤1350 °C) | MAX31856 (K/N/S/R/B/E/J/T, richer fault detection) | Diagnosability, [LINK: SWR-SAF-04] |
| PID gains | Manually tuned, documented by experiment | Automatic tuning on-device (FR-TUN ([LINK: SECT-3-3])) | Explicit requirement |
| Storage | SPIFFS on internal flash, microSD board recommended | Dedicated raw partitions, fixed slots for programs and run records and a circular ring for the log, no SD card and no filesystem ([LINK: UR-CON-03]) | Explicit requirement |
| Heater current | Optional 30 A/1 V power meter, not used for protection | **Mandatory** current transformer driving relay fail-on / fail-off detection and weld discrimination (FR-CUR ([LINK: SECT-3-12]), [LINK: SWR-SAF-25]–[LINK: SWR-SAF-30]) | Explicit requirement; resolves [LINK: OQ-02] |
| Architecture | Arduino sketch, hardware access throughout | Layered, HAL-isolated, host-testable core (TR ([LINK: SECT-7])) | Explicit requirement: design for testability |
No PIDKiln source code is copied. Safe Kiln Controller is licensed GPL-3.0-or-later, the
same licence as PIDKiln, so derivation remains possible in either direction.
<<<
[[/SECTION]]
[[/SECTION]]
[[SECTION]]
UID: SECT-2
TITLE: 2. System overview
[[SECTION]]
UID: SECT-2-1
TITLE: 2.1 Context
[TEXT]
STATEMENT: >>>
```mermaid
flowchart LR
OP(["Operator"])
subgraph KC["Safe Kiln Controller device"]
MCU["ESP32-S3<br/>controller"]
OLED["128x64 OLED"]
ENC["Encoder<br/>+ button"]
BUZ["Buzzer"]
end
subgraph KILN["Kiln"]
TC1["Chamber<br/>thermocouple"]
ELEM["Heating<br/>elements"]
end
SSR["SSR"]
CONT["Safety<br/>contactor"]
CT["Current<br/>transformer"]
TC2["Enclosure<br/>thermocouple"]
BROWSER(["Browser on<br/>phone / PC"])
MAINS(["Mains supply"])
OP -->|turn / press| ENC
OLED -->|temperatures, state| OP
BUZ -->|alarm| OP
TC1 -->|mV| MCU
TC2 -->|mV| MCU
MCU -->|duty| SSR
MCU -->|heat enable| CONT
MAINS --> CONT --> SSR --> CT --> ELEM
CT -->|heater current| MCU
ELEM -.->|heat| TC1
MCU <-->|WiFi / HTTP| BROWSER
```
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-2-2
TITLE: 2.2 Operating modes
[TEXT]
STATEMENT: >>>
```mermaid
stateDiagram-v2
[*] --> Idle
Idle --> RunningProgram: start program
Idle --> Manual: set fixed target
Idle --> Autotune: start tuning
RunningProgram --> Paused: pause
Paused --> RunningProgram: resume
RunningProgram --> Complete: last segment done
Manual --> Idle: stop
Autotune --> Idle: finished / aborted
Complete --> Idle: acknowledge
RunningProgram --> Fault: safety trip
Manual --> Fault: safety trip
Autotune --> Fault: safety trip
Paused --> Fault: safety trip
Fault --> Idle: acknowledge (heat off, cooled)
```
| Mode | Description |
|---|---|
| **Idle** | Heating disabled, temperature monitored and displayed. |
| **Running** | Executing a firing program under PID control. |
| **Paused** | Program suspended, heating off, elapsed time frozen; resumable. |
| **Manual** | PID holds a single operator-entered target temperature indefinitely. |
| **Autotune** | Automatic PID tuning procedure in progress. |
| **Complete** | Program finished normally; cooling, awaiting acknowledgement. |
| **Fault** | A safety condition tripped. Heating de-energised and latched off. |
<<<
[[/SECTION]]
[[SECTION]]
UID: SECT-2-3
TITLE: 2.3 Primary use cases
[TEXT]
STATEMENT: >>>
| UC | Actor | Description |
|---|---|---|
| UC-1 | Operator | Load a stored firing program, review it, start it, and walk away. |
| UC-2 | Operator | Watch current vs. target temperature on the local display. |
| UC-3 | Operator | Open the web interface on a phone to see live status and the curve traced so far. |
| UC-4 | Operator | Create or edit a firing program in the browser and save it on the device. |
| UC-5 | Operator | Change the target temperature or ramp of a *running* program. |
| UC-6 | Operator | Abort a running firing from either the device or the browser. |
| UC-7 | Operator | Run automatic PID tuning after installing the controller on a new kiln. |
| UC-8 | Operator | Review the logged temperature trace of a previous firing and export it. |
| UC-9 | System | Detect a failed element, shorted SSR, welded contactor or broken thermocouple, de-energise the kiln and alarm. |
| UC-12 | Operator | Fit a clip-on current transformer to a heater conductor and calibrate it against a reference meter. |
| UC-13 | Operator | See that this firing is drawing less current than usual and conclude an element is failing, before it ruins a load. |
| UC-10 | Installer | Provision WiFi credentials and configure kiln limits on first power-up. |
| UC-11 | Maintainer | Update firmware over WiFi. |
<<<
[[/SECTION]]
[[/SECTION]]
[[SECTION]]
UID: SECT-3
TITLE: 3. Functional requirements
[[SECTION]]
UID: SECT-3-1
TITLE: 3.1 Temperature acquisition (FR-ACQ)
[REQUIREMENT]
UID: SWR-ACQ-01
STATEMENT: >>>
Chamber temperature shall be measured with a MAX31856 thermocouple front end over SPI **by the independent supervisor**, and reported to the controller over the link of [LINK: SYS-HW-27] at not less than 4 Hz. The **enclosure** channel's MAX31856 remains the controller's own, on the controller's bus.
**Amended 2026-10-10 with the supervisor (SWA-22).** This said "the system shall measure", which was accurate when one microcontroller read both front ends. It no longer is, and the difference matters to every requirement downstream: the controller does not own the chamber front end, cannot configure it ([LINK: SWR-ACQ-02]), and has no access to it other than a frame arriving on a serial line.
What that makes the controller's obligation here:
- **A report is a sample.** The link's rate is the controller's sample rate; there is nothing behind it to poll faster.
- **Silence is a sensor fault, not a comms problem.** A link that has gone quiet, or that is repeating a sequence number, presents to the controller exactly as a front end that has stopped answering, and is handled by [LINK: SWR-SAF-04]'s grace and latch rather than retried. That is tested end to end: the kiln is heating, the link stops, the fault latches and the contactor opens.
- **A reading is not trusted further than its source.** The supervisor's own fault bits and its trip reason come up the same link and are displayed, never acted on as permission.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-02
STATEMENT: >>>
The **chamber** thermocouple shall be type **K**, and its type shall not be configurable.
The chamber front end is read by the independent safety supervisor, which applies a hard-coded temperature backstop ([LINK: SWR-SAF-23]). The MAX31856 linearises according to a type register, so whoever sets that register determines what the supervisor's temperature *means*: with the supervisor expecting type K and a type S couple fitted, the reading at 1300 °C is roughly a quarter of type K's output and the backstop would never fire. Tripping on raw thermovoltage does not escape this, because a threshold set for the least sensitive type never fires for the most sensitive and one set for the most sensitive fires at a few hundred degrees for the rest.
The other types are therefore a documented limitation of the supervised product rather than a silent hazard. The **enclosure** channel's type remains configurable, that channel not being in the supervisor's remit.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-03
STATEMENT: >>>
The system shall acquire chamber temperature at a rate of at least **4 Hz**, and the acquisition period shall be constant to within ±10 %.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-04
STATEMENT: >>>
The system shall apply cold-junction compensation using the MAX31856 internal cold-junction sensor.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-05
STATEMENT: >>>
The system shall report chamber temperature with a resolution of **0.1 °C** or finer and a usable range of **−20 °C to 1350 °C** for type K.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-06
STATEMENT: >>>
The system shall configure the front-end's line-frequency notch filter to **50 Hz or 60 Hz** according to configuration, defaulting to 50 Hz.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-07
STATEMENT: >>>
The system shall apply a configurable first-order low-pass filter to the measurement used for control, with a time constant of 0–30 s (default 2 s), and shall log the *unfiltered* value alongside it.
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-08
STATEMENT: >>>
The system shall apply a configurable calibration offset of −50.0 … +50.0 °C and a gain factor of 0.90 … 1.10 to the chamber reading.
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-09
STATEMENT: >>>
The system shall measure enclosure/electronics temperature with a second, independently configurable thermocouple channel.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-10
STATEMENT: >>>
The system shall read and expose the front-end fault register on every conversion, distinguishing at minimum: open circuit, short to VCC, short to GND, cold-junction out of range, thermocouple out of range, over/under-voltage.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-11
STATEMENT: >>>
The system shall compute the rate of temperature change (°C/h) from a regression over a configurable window of 10–300 s (default 60 s).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-ACQ-12
STATEMENT: >>>
On a transient acquisition error the system shall retain the last valid reading for a configurable grace period of 1–30 s (default 5 s) before declaring a sensor fault ([LINK: SWR-SAF-04]).
<<<
PRIORITY: M
VERIFICATION: T
[[/SECTION]]
[[SECTION]]
UID: SECT-3-2
TITLE: 3.2 Control loop (FR-CTL)
[REQUIREMENT]
UID: SWR-CTL-01
STATEMENT: >>>
The system shall implement a PID controller producing a heating duty in the range 0–100 %.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-02
STATEMENT: >>>
The controller shall execute at a fixed, configurable period of 0.25–5 s (default 1 s), independent of the acquisition rate.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-03
STATEMENT: >>>
The controller shall use configurable gains Kp, Ki, Kd with the ranges and units defined in [LINK: SWR-CFG-02].
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-04
STATEMENT: >>>
The controller shall compute the derivative term from the *measurement*, not the error, so that a setpoint step does not produce a derivative kick.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-05
STATEMENT: >>>
The controller shall clamp its integral term and shall suspend integration while the output is saturated (conditional-integration anti-windup).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-06
STATEMENT: >>>
On entering or leaving manual/automatic control the controller shall transfer bumplessly: the output shall not step by more than 1 % as a direct result of the mode change.
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-07
STATEMENT: >>>
The system shall convert duty to heater switching by **time-proportional control** over a configurable window of 0.5–30 s (default 2 s).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-08
STATEMENT: >>>
The system shall enforce a configurable minimum on-time and minimum off-time (0–2000 ms, default 100 ms) and shall round a duty that cannot satisfy them to fully off or fully on.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-09
STATEMENT: >>>
The system shall generate the setpoint from the active program by linear interpolation in time, so that the setpoint advances at the segment's ramp rate rather than stepping to the segment target.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-10
STATEMENT: >>>
The system shall support a ramp rate of 1–9999 °C/h, where a configured rate of **0 means "as fast as the kiln allows"** (setpoint follows the segment target directly).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-11
STATEMENT: >>>
The system shall implement **hold-back**: when |SP − PV| exceeds a configurable band (0–200 °C, default 0 disables), the setpoint shall stop advancing and the segment timer shall pause until PV re-enters the band.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-12
STATEMENT: >>>
The system shall treat a dwell segment as complete only after the dwell time has elapsed *and* PV has been within a configurable tolerance band of the target (0.5–50 °C, default 5 °C) for that duration, subject to [LINK: SWR-CTL-11].
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-13
STATEMENT: >>>
The system shall never command heating during a cooling segment; a segment whose target is below the current temperature shall be executed as a passive cooling ramp with the setpoint tracked only as an upper bound.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-14
STATEMENT: >>>
The system shall support a manual mode in which the PID holds a single operator-supplied target temperature.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-15
STATEMENT: >>>
The system shall expose PID internals (P, I, D contributions, error, duty, saturation flag) for diagnostics and logging.
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-CTL-16
STATEMENT: >>>
The system shall limit the commanded duty to a configurable maximum of 10–100 % (default 100 %), to allow derating an over-powered kiln.
<<<
PRIORITY: C
VERIFICATION: T
[[/SECTION]]
[[SECTION]]
UID: SECT-3-3
TITLE: 3.3 Automatic PID tuning (FR-TUN)
[REQUIREMENT]
UID: SWR-TUN-01
STATEMENT: >>>
The system shall provide an automatic PID tuning procedure that determines Kp, Ki and Kd without operator calculation.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-02
STATEMENT: >>>
Tuning shall use the **relay (Åström–Hägglund) method** [R5]: the controller drives a bounded on/off limit cycle about a tuning setpoint and measures the ultimate gain *Ku* and ultimate period *Tu* from the resulting oscillation.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-03
STATEMENT: >>>
The operator shall specify the tuning setpoint; the system shall reject a setpoint above the configured maximum temperature or below ambient + 50 °C.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-04
STATEMENT: >>>
The relay output shall be bounded by a configurable output amplitude *d* (10–100 % duty, default 50 %) and a configurable hysteresis (0.1–20 °C, default 1 °C).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-05
STATEMENT: >>>
The system shall discard the first oscillation cycle and shall require at least **3** further cycles whose successive periods agree within 15 % and whose amplitudes agree within 20 % before accepting a result.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-06
STATEMENT: >>>
The system shall derive gains using selectable rules, **Ziegler–Nichols** (classic, aggressive) and **Tyreus–Luyben** (conservative, default), and shall present both candidate gain sets to the operator.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-07
STATEMENT: >>>
The system shall abort tuning and enter Fault if any safety requirement in §5 ([LINK: SECT-5]) trips, if no valid oscillation is identified within a configurable timeout (10–480 min, default 120 min), or if the operator cancels.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-08
STATEMENT: >>>
Aborted tuning shall leave the previously stored gains unchanged.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-09
STATEMENT: >>>
The system shall not store tuning results automatically; the operator shall explicitly accept a result before it replaces the active gains.
<<<
PRIORITY: M
VERIFICATION: D
[REQUIREMENT]
UID: SWR-TUN-10
STATEMENT: >>>
The system shall report live tuning progress (phase, cycles captured, measured Ku/Tu, elapsed time) and shall record the tuning oscillation in the data log like any other run.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-11
STATEMENT: >>>
The system shall store the provenance of the active gains: manual, or tuned (with rule, Ku, Tu, tuning setpoint and timestamp).
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-TUN-12
STATEMENT: >>>
The system shall warn the operator that the kiln must be loaded representatively and the lid closed before tuning, because the identified model includes the load.
<<<
PRIORITY: S
VERIFICATION: I
[REQUIREMENT]
UID: SWR-TUN-13
STATEMENT: >>>
The system shall support storing up to **4** named gain sets (e.g. per firing range) and selecting one per program.
<<<
PRIORITY: C
VERIFICATION: T
[[/SECTION]]
[[SECTION]]
UID: SECT-3-4
TITLE: 3.4 Firing programs (FR-PRG)
[REQUIREMENT]
UID: SWR-PRG-01
STATEMENT: >>>
A firing program shall consist of a name, an optional description, and an ordered list of **1–32 segments**.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-02
STATEMENT: >>>
Each segment shall comprise: target temperature (0–1350 °C), ramp rate (0–9999 °C/h, 0 = maximum), and dwell time (0–5999 min).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-03
STATEMENT: >>>
Each segment shall optionally carry a flag requiring **operator acknowledgement** before the program advances past it (e.g. to crack the lid for venting).
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-04
STATEMENT: >>>
**Withdrawn 2026-10-10.** This required at least 20 programs in non-volatile storage, persisting across power loss and firmware update.
It was the last requirement standing on the authoring path that [LINK: SWR-PRG-07], [LINK: SWR-PRG-08] and [LINK: SWR-PRG-10] were withdrawn with. With nothing on the device able to create or edit a program, the storage held a copy of the three examples that arrive in the image ([LINK: SWR-PRG-09]) and nothing else: persistence of something already persistent, in a medium that wears out, behind a seeding path that could fail on a first boot and a store that could fail to mount.
So the programs are read from the firmware. What that *removes* is worth stating, because this is a deletion that makes the device better rather than smaller:
- A device whose flash will not mount now still has its programs. It used to serve `503` for the list of programs it was carrying in its own image.
- A factory reset ([LINK: SWR-CFG-09]) no longer costs the operator their programs. The partition holds run history, and losing history is what a factory reset is for.
- The first boot has nothing to get wrong. Seeding was idempotent and tested, and it was still a write to flash on every power-on of a brand-new device.
"Persisting across a firmware update" is now trivially true in the only sense left: the programs are part of what the update installs. A user who wants a different curve edits `kiln_core/profile` and builds, which is the cost [LINK: SWR-PRG-09] states plainly.
The 20-slot figure is gone with the requirement. `kiln_core/fileslots` still carries 64 regions and the run index still uses 20 of them ([LINK: SWR-LOG-09]), so the partition is now a third used rather than two thirds. That is recorded in architecture 10.6 and deliberately not acted on: shrinking the partition is a flash-layout change that breaks every device already flashed, to recover space nothing needs.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-05
STATEMENT: >>>
The system shall validate a program on start, rejecting it with a specific reason if: no segments; any target above the configured maximum temperature; any field out of range; total predicted duration above 168 h.
**Still required after [LINK: SWR-PRG-04]'s withdrawal, and the reason is the configured maximum.** The programs are compiled in and therefore trusted as *data*, but `safety.max_temp_c` is set by the operator and can be lowered below a program's peak; validation on start is what refuses that firing rather than running it into a ceiling. A test asserts that every compiled-in example validates against the default maximum, because an example that cannot start is one an operator discovers by selecting it.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-06
STATEMENT: >>>
The system shall compute and present the predicted total duration and the predicted end time of a program before it is started.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-07
STATEMENT: >>>
**Withdrawn 2026-10-09: programs are pre-compiled and are not edited anywhere.** This required creating, reading, updating, renaming, duplicating and deleting programs through the web interface.
Half of it was already gone: [LINK: SWR-WEB-26] made the interface read-only, so nothing over the network could create or change a program. The rest goes with the decision that the set of firing profiles is **fixed at build time** ([LINK: SWR-PRG-09]), which answers `OQ-09` by removing the question rather than by choosing one of the editors it offered.
What that buys, and it is the reason to prefer it: there is no authoring path to secure, no file format to validate, no import to get wrong, and no editor to build on a rotary encoder. What it costs is stated plainly in [LINK: SWR-PRG-09]: a user who wants a curve of their own builds one into the firmware.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-08
STATEMENT: >>>
**Withdrawn 2026-10-09 with [LINK: SWR-PRG-07].** This required exporting and importing a program as a documented JSON file.
Import is authoring by another name, and the set of profiles is fixed at build time. Export has no purpose on its own: what a user would export is already in the source, under version control, readable.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-09
STATEMENT: >>>
The system shall ship with at least **3** example programs (e.g. bisque cone 06, glaze cone 6, glass fusing), compiled into the firmware and read-only.
**These are the only firing programs the device has**, as of the 2026-10-09 decision that withdrew [LINK: SWR-PRG-07], [LINK: SWR-PRG-08] and [LINK: SWR-PRG-10]. A user who wants a different curve adds it here and builds, which is a real cost and is the honest consequence of having no authoring path at all: it puts a compiler between a potter and a firing schedule.
The trade was taken deliberately. Every authoring route costs something this design is not willing to spend: over the network reopens a write path that [LINK: SWR-WEB-26] closed, at the display means editing five segments of target, rate and dwell on a rotary encoder, and an import file is a parser accepting operator-supplied data on the component that commands a heater.
<<<
PRIORITY: S
VERIFICATION: I
[REQUIREMENT]
UID: SWR-PRG-10
STATEMENT: >>>
**Withdrawn 2026-10-09 with [LINK: SWR-PRG-07].** This required editing the remaining segments of a running program while rejecting edits to the current or completed ones.
It was the most delicate requirement in this section, because it asks the run controller to accept a change to the thing it is executing, and it is now moot: there is no editor and no segment to change. [LINK: SWR-RUN-07]'s abort remains the way to stop a firing that is doing the wrong thing.
<<<
PRIORITY: S
VERIFICATION: T
[REQUIREMENT]
UID: SWR-PRG-11
STATEMENT: >>>
The system shall record, for each run, the program content as executed, so that a later program edit does not invalidate the historical record.
<<<
PRIORITY: M
VERIFICATION: T
[[/SECTION]]
[[SECTION]]
UID: SECT-3-5
TITLE: 3.5 Run control (FR-RUN)
[REQUIREMENT]
UID: SWR-RUN-01
STATEMENT: >>>
The system shall implement the state machine of §2.2 ([LINK: SECT-2-2]), and every state transition shall be logged with a timestamp and cause.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-02
STATEMENT: >>>
The system shall start a program only from Idle, and only after validation ([LINK: SWR-PRG-05]) and a self-check of sensor and output health has passed.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-03
STATEMENT: >>>
The system shall support pause and resume; on pause, heating shall be disabled and all program timers frozen.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-04
STATEMENT: >>>
The operator shall be able to abort a run at any time from the local display **and** from the web interface; abort shall de-energise heating within **1 s**.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-05
STATEMENT: >>>
The system shall expose, while running: state, segment index and count, setpoint, process value, duty, rate of change, elapsed time, time remaining in segment, predicted end time, and hold-back status.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-06
STATEMENT: >>>
On program completion the system shall disable heating, sound the alarm for a configurable duration (0–600 s, default 4 s), and enter Complete.
**Amended 2026-10-09.** The default was 30 s, which with the completion pattern of [LINK: SWR-SAF-20] is fifteen repetitions of it. A firing that has just finished correctly is good news, and a notification is what it wants rather than half a minute of chirping, so the default is now one burst's worth. The range is unchanged: an operator who wants the kiln to keep saying so until somebody comes can still set it, and 0 silences the completion annunciation without touching the fault one.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-07
STATEMENT: >>>
The system shall record a **run record** for every run (program executed, gains used, start and end time, end reason, log extent, and the reference heater current established for the run, [LINK: SWR-CUR-08]).
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-08
STATEMENT: >>>
On restart after an unexpected power loss during a run, the system shall apply the configured recovery policy: **abort** (default), or **resume** if the outage was shorter than a configurable limit (1–120 min, default 15 min) *and* PV is within a configurable band (5–200 °C, default 50 °C) of the setpoint at the time of interruption.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-RUN-09
STATEMENT: >>>
The system shall persist enough run state at least every **10 s** to support [LINK: SWR-RUN-08], without exceeding the flash endurance budget of [LINK: SWR-NFR-14].
<<<
PRIORITY: M
VERIFICATION: A, T
[REQUIREMENT]
UID: SWR-RUN-10
STATEMENT: >>>
The system shall refuse to start a run while a fault is latched, while autotune is active, or while the enclosure temperature exceeds its limit.
<<<
PRIORITY: M
VERIFICATION: T
[[/SECTION]]
[[SECTION]]
UID: SECT-3-6
TITLE: 3.6 Local display and input (FR-HMI)
[REQUIREMENT]
UID: SWR-HMI-01
STATEMENT: >>>
The system shall drive a 128×64 monochrome OLED (SSD1306/SH1106 class) over I²C.
<<<
PRIORITY: M
VERIFICATION: T
[REQUIREMENT]
UID: SWR-HMI-02
STATEMENT: >>>
The default screen shall show, simultaneously and unambiguously, the **current chamber temperature** and the **target temperature**.
<<<
PRIORITY: M
VERIFICATION: D
[REQUIREMENT]
UID: SWR-HMI-03
STATEMENT: >>>
The current temperature shall be rendered in the largest font on the screen, legible at 2 m.
<<<
PRIORITY: M