1"""Serial-frame validator helper for the ELT CH4 (methane) sensor.
2
3Standalone development utility for debugging the ASCII-to-numeric
4conversion of ELT CH4 sensor serial output. The module simulates a raw
5byte stream as it would be received by
6:class:`SensorBase.SensorBase.GenericSensor`-style consumers via the
7production driver in :mod:`drivers.Elt_ch4.Elt_ch4`, and verifies that
8numeric values are correctly extracted from the ASCII payload.
9
10This is a pure validation helper — it has no side effects on hardware
11and is not used in production. It is safe to import and execute in unit
12tests and doctests without a serial port present.
13
14Example:
15 >>> from drivers.Elt_ch4.check_string import convert_elt_data
16 >>> convert_elt_data("__1500_ppm") # doctest: +SKIP
17 string char:_ False
18 string char:_ False
19 string char:1 True
20 1
21 ...
22 Sensor Val:1500
23
24Note:
25 Mirrors the parsing logic of
26 :meth:`drivers.Elt_ch4.Elt_ch4.Elt_ch4.convert_elt_data` but prints
27 intermediate state to ``stdout`` for human inspection rather than
28 returning a value.
29"""
30
31
[docs]
32def convert_elt_data(string_data: str) -> None:
33 """Parse an ASCII sensor frame and print the extracted ppm value.
34
35 Debugging counterpart to
36 :meth:`drivers.Elt_ch4.Elt_ch4.Elt_ch4.convert_elt_data`. Iterates
37 over each character in ``string_data``, prints whether the
38 character is numeric, accumulates the digits into a single integer,
39 and prints the resulting ppm value. Useful for verifying frame
40 layout when bringing up a new sensor unit.
41
42 Args:
43 string_data (str): UTF-8 decoded ASCII payload from the ELT
44 sensor's serial output (e.g. ``"__1500_ppm"``).
45
46 Returns:
47 None: The parsed value is printed to ``stdout``; nothing is
48 returned to the caller.
49
50 Raises:
51 ValueError: If ``string_data`` contains no numeric characters,
52 because ``int("")`` cannot be evaluated when computing
53 ``final_sensor_value``.
54
55 Example:
56 >>> convert_elt_data("12")
57 string char:1 True
58 1
59 string char:2 True
60 2
61 Sensor Val:12
62
63 Note:
64 Like the production parser, digits are concatenated rather than
65 tokenised: ``"1 2"`` becomes ``12``, not ``1`` and ``2``.
66 """
67 sensor_value = ""
68 for char in string_data:
69 print(f"string char:{char} {char.isnumeric()}")
70 if char.isnumeric():
71 print(int(char))
72 sensor_value += str(int(char))
73 final_sensor_value = int(sensor_value)
74 print(f"Sensor Val:{final_sensor_value}")
75
76
[docs]
77def main():
78 """Run :func:`convert_elt_data` against a canned ELT byte payload.
79
80 Reconstructs a representative ELT CH4 serial frame from a list of
81 single-byte ``bytes`` objects, decodes the stream as UTF-8, and
82 forwards the resulting string to :func:`convert_elt_data` for
83 parsing. Acts as the script entry point so the file can be run with
84 ``python check_string.py``.
85
86 Args:
87 None.
88
89 Returns:
90 None: Output is produced via ``print`` inside
91 :func:`convert_elt_data`.
92
93 Raises:
94 UnicodeDecodeError: If the canned ``list_raw_data`` is altered
95 to include a non-UTF-8 byte.
96 ValueError: Propagated from :func:`convert_elt_data` when the
97 decoded frame contains no digits.
98
99 Example:
100 >>> main()
101 string char:_ False
102 string char:_ False
103 string char:1 True
104 1
105 string char:5 True
106 5
107 string char:0 True
108 0
109 string char:0 True
110 0
111 string char:_ False
112 string char:p False
113 string char:p False
114 string char:m False
115 Sensor Val:1500
116
117 Note:
118 The alternative ``list_raw_data`` definition kept as a comment
119 documents a real-world capture that intentionally exercises the
120 non-printable byte path; it is left in place for future
121 regression checks.
122 """
123 # list_raw_data = [b'\x16', b'5', b'\x0b', b'\x00', b'\x00', b'\x00', b'\r', b'\x00', b'\x00', b'\x00', b'\x0f', b'\x00', b'\x00', b'\x00', b'\x14', b'\x00', b'\x00', b'\x00', b'\x14', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x81', b'\xfa', b'\x00', b'\x00', b'\x01', b'\x8d', b'\x00', b'\x00', b'\x00', b'\x87', b'\x00', b'\x00', b'\x00', b'.', b'\x00', b'\x00', b'\x00', b'\x14', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x00', b'\x02', b'\x92']
124 list_raw_data = [b"\x5f", b"\x5f", b"\x31", b"\x35", b"\x30", b"\x30", b"\x5f", b"\x70", b"\x70", b"\x6d"]
125 data = ""
126 for _data in list_raw_data:
127 data += _data.decode("utf-8")
128 # convert_elt_data(" 1500 _ ppm")
129 convert_elt_data(data)
130
131
132if __name__ == "__main__":
133 main()