1
- ### clue-mutlitemplogger.py v1.1
1
+ ### clue-mutlitemplogger.py v1.2
2
2
### Measure temperature from multiple sensors and log to CIRCUITPY
3
3
4
+ ### This now writes every 6 minutes to REDUCE THE WEAR on the flash chip
5
+ ### (replacing this involves SMD soldering!)
6
+ ### See https://forums.adafruit.com/viewtopic.php?f=65&t=175527
7
+
4
8
### Tested with Adafruit CLUE and CircuitPython 6.1.0
5
9
6
10
### MIT License
31
35
32
36
import microcontroller
33
37
import board
34
- import busio
35
38
from adafruit_onewire .bus import OneWireBus
36
39
import adafruit_ds18x20
37
40
import adafruit_bmp280
49
52
50
53
MAX_AIN = 2 ** 16 - 1
51
54
55
+ VERBOSE = False
56
+
57
+ ### Measure every 10 seconds but do not write to CIRCUITPY at this
58
+ ### rate as the flash does not have wear-levelling and
52
59
count = 3
53
60
interval = 10
54
61
interval_ns = interval * 1000 * 1000 * 1000
55
- verbose = False
62
+ write_buffer_lines = 108 ### 8640 bytes every 108/3*10=360 seconds
63
+ pending_writes = []
64
+
56
65
console = True
57
66
58
67
65
74
### NeoPixel colour during measurement
66
75
### Bright values may be useful if powered from a
67
76
### USB power bank with low-current auto off
77
+ RECORDING = 0xff0000
68
78
READING = 0x00ff00 + (0x0000ff if data_file else 0 )
69
79
BLACK = 0x000000
70
80
71
81
82
+ ### First value might be questionable with a high impedance source
83
+ ### due to input multiplexing
72
84
def get_voltage (ain , samples = 500 ):
73
85
return sum ([ain .value for _ in range (samples )]) / (samples * MAX_AIN ) * vref
74
86
@@ -84,7 +96,7 @@ def find_DS18X20(bus, verbose=True):
84
96
if verbose :
85
97
for dev in devices :
86
98
print ("ROM = {}\t Family = 0x{:02x}" .format ([hex (i ) for i in dev .rom ],
87
- dev .family_code ))
99
+ dev .family_code ))
88
100
return devices [0 ] if devices else None
89
101
90
102
@@ -102,8 +114,8 @@ def measure_temps(sensor_list=None):
102
114
ow_bus = OneWireBus (DS18X20_PIN )
103
115
bmp280 = adafruit_bmp280 .Adafruit_BMP280_I2C (i2c )
104
116
sht31d = adafruit_sht31d .SHT31D (i2c )
105
- ds18b20 = adafruit_ds18x20 .DS18X20 (ow_bus ,
106
- find_DS18X20 (ow_bus , verbose = verbose ))
117
+ ds18b20 = adafruit_ds18x20 .DS18X20 (ow_bus ,
118
+ find_DS18X20 (ow_bus , verbose = VERBOSE ))
107
119
pixel = neopixel .NeoPixel (board .NEOPIXEL , 1 )
108
120
109
121
ntc_ain = AnalogIn (NTC_PIN )
@@ -125,15 +137,21 @@ def measure_temps(sensor_list=None):
125
137
126
138
def output (text , * , pad = " " , pad_len = 0 , end = b"\x0d \x0a " , encoding = "ascii" ):
127
139
if pad and pad_len :
128
- out_text = text + " " * (pad_len - len (text ) - len (end ))
140
+ out_text = text + " " * (pad_len - len (text ) - len (end ))
129
141
else :
130
- out_text = text
131
-
142
+ out_text = text
143
+
132
144
if console :
133
145
print (out_text )
134
146
if data_file :
135
- data_file .write (out_text .encode (encoding ) + end )
136
- data_file .flush ()
147
+ pending_writes .append (out_text .encode (encoding ) + end )
148
+ if len (pending_writes ) >= write_buffer_lines :
149
+ pixel [0 ] = RECORDING
150
+ for line in pending_writes :
151
+ data_file .write (line )
152
+ data_file .flush ()
153
+ pending_writes .clear ()
154
+ pixel [0 ] = BLACK
137
155
138
156
139
157
### 80 chars minus CRLF
@@ -145,29 +163,29 @@ def output(text, *, pad=" ", pad_len=0, end=b"\x0d\x0a", encoding="ascii"):
145
163
output (HEADER , pad_len = FIXED_WIDTH )
146
164
147
165
148
- last_loop_t = 0
166
+ last_loop_ns = 0
149
167
150
- backlight_cycle_dur_ns = 1800e9
168
+ backlight_cycle_dur_ns = 7200e9
151
169
backlight_cycle = [1.0 , 0.0 , 0.0 , 0.125 , 0.25 , 0.5 ]
152
170
153
- start_loop_t = time .monotonic_ns ()
171
+ start_loop_ns = time .monotonic_ns ()
154
172
while True :
155
173
while True :
156
- now_t = time .monotonic_ns ()
157
- if now_t > last_loop_t + interval_ns :
174
+ now_ns = time .monotonic_ns ()
175
+ if now_ns > last_loop_ns + interval_ns :
158
176
break
159
- last_loop_t = now_t
177
+ last_loop_ns = now_ns
160
178
161
179
### Cycle the backlight through the brightness values stored in list
162
- phase , _ = math .modf ((now_t - start_loop_t ) / backlight_cycle_dur_ns )
180
+ phase , _ = math .modf ((now_ns - start_loop_ns ) / backlight_cycle_dur_ns )
163
181
backlight = backlight_cycle [min (int (phase * len (backlight_cycle )),
164
182
len (backlight_cycle ) - 1 )]
165
183
set_backlight (backlight )
166
184
167
185
### Take a few measurements and print / log them
168
186
for _ in range (count ):
169
- in_start_t = time .monotonic_ns ()
187
+ in_start_ns = time .monotonic_ns ()
170
188
temps = measure_temps ()
171
- data_as_text = ("{:d},{:.3f}," .format (in_start_t , backlight )
189
+ data_as_text = ("{:d},{:.3f}," .format (in_start_ns , backlight )
172
190
+ "," .join ([str (temp ) for temp in temps .values ()]))
173
191
output (data_as_text , pad_len = FIXED_WIDTH )
0 commit comments