8 import schedule
# https://pypi.org/project/schedule/ via https://stackoverflow.com/a/16786600
9 import datetime
# http://stackoverflow.com/questions/2150739/ddg#28147286
11 # Transitional fix for breaking change in LTR559
12 from ltr559
import LTR559
17 from bme280
import BME280
18 from enviroplus
import gas
19 from subprocess
import PIPE
, Popen
21 from PIL
import ImageDraw
22 from PIL
import ImageFont
23 from fonts
.ttf
import RobotoMedium
as UserFont
28 format
='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
30 datefmt
='%Y-%m-%d %H:%M:%S')
32 logging
.info("""all-in-one.py - Displays readings from all of Enviro plus' sensors
37 varLenBufferTTL
= int((2*24*60*60)*10**9) # time-to-live in nanoseconds
39 # BME280 temperature/pressure/humidity sensor
42 # Create ST7735 LCD display class
43 st7735
= ST7735
.ST7735(
49 #rotation=90, # flip upside down wrt enviro+ default orientation
57 HEIGHT
= st7735
.height
59 # Set up canvas and font
60 img
= Image
.new('RGB', (WIDTH
, HEIGHT
), color
=(0, 0, 0))
61 draw
= ImageDraw
.Draw(img
)
62 path
= os
.path
.dirname(os
.path
.realpath(__file__
))
64 font
= ImageFont
.truetype(UserFont
, font_size
)
66 font2
= ImageFont
.truetype(UserFont
, font2_size
)
70 # The position of the top bar
74 # Displays data and text on the 0.96" LCD
75 def display_text(variable
, data
, unit
):
76 # Maintain length of list
77 values
[variable
] = values
[variable
][1:] + [data
]
78 # Scale the values for the variable between 0 and 1
79 vmin
= min(values
[variable
])
80 vmax
= max(values
[variable
])
81 colours
= [(v
- vmin
+ 1) / (vmax
- vmin
+ 1) for v
in values
[variable
]]
82 # Format the variable name and value
83 message
= "{}: {:.1f} {}".format(variable
[:4], data
, unit
)
85 draw
.rectangle((0, 0, WIDTH
, HEIGHT
), (255, 255, 255))
86 for i
in range(len(colours
)):
87 # Convert the values to colours from red to blue
88 colour
= (1.0 - colours
[i
]) * 0.6
89 r
, g
, b
= [int(x
* 255.0) for x
in colorsys
.hsv_to_rgb(colour
, 1.0, 1.0)]
90 # Draw a 1-pixel wide rectangle of colour
91 draw
.rectangle((i
, top_pos
, i
+ 1, HEIGHT
), (r
, g
, b
))
92 # Draw a line graph in black
93 line_y
= HEIGHT
- (top_pos
+ (colours
[i
] * (HEIGHT
- top_pos
))) + top_pos
94 draw
.rectangle((i
, line_y
, i
+ 1, line_y
+ 1), (0, 0, 0))
95 # Write the text at the top in black
96 draw
.text((0, 0), message
, font
=font
, fill
=(0, 0, 0))
99 # Displays data and text on the 0.96" LCD
100 def display_text2(variable
, data
, unit
, values
):
101 # Scale the values for the variable between 0 and 1
102 #print('DEBUG:len(values[' + str(variable) + ']):' + str(len(values[variable])))
103 #print('DEBUG:values[' + str(variable) + ']:' + str(values[variable]))
104 vmin
= min(values
[variable
])
105 vmax
= max(values
[variable
])
106 colours
= [(v
- vmin
+ 1) / (vmax
- vmin
+ 1) for v
in values
[variable
]]
107 # Format the variable name and value
108 message
= "{}: {:.1f} {}".format(variable
[:4], data
, unit
)
109 #message = "{}: {:.1f} {}".format(variable[:4], values[variable][-1], unit)
110 logging
.info(message
)
111 draw
.rectangle((0, 0, WIDTH
, HEIGHT
), (255, 255, 255))
112 for i
in range(len(colours
)):
113 # Convert the values to colours from red to blue
114 colour
= (1.0 - colours
[i
]) * 0.6
115 r
, g
, b
= [int(x
* 255.0) for x
in colorsys
.hsv_to_rgb(colour
, 1.0, 1.0)]
116 # Draw a 1-pixel wide rectangle of colour
117 draw
.rectangle((i
, top_pos
, i
+ 1, HEIGHT
), (r
, g
, b
))
118 # Draw a line graph in black
119 line_y
= HEIGHT
- (top_pos
+ (colours
[i
] * (HEIGHT
- top_pos
))) + top_pos
120 draw
.rectangle((i
, line_y
, i
+ 1, line_y
+ 1), (0, 0, 0))
121 # Write the text at the top in black
122 draw
.text((0, 0), message
, font
=font
, fill
=(0, 0, 0))
124 maxMsg
= "MAX:{:.1f}".format(vmax
)
125 durMsg
= "HR:{:.1f}".format(span_time_h
)
126 minMsg
= "MIN:{:.1f}".format(vmin
)
127 maxMsg_y
= int( ((HEIGHT
- top_pos
)/(HEIGHT
))*(HEIGHT
*(1/4)) + top_pos
- (font2_size
/2) )
128 durMsg_y
= int( ((HEIGHT
- top_pos
)/(HEIGHT
))*(HEIGHT
*(2/4)) + top_pos
- (font2_size
/2) )
129 minMsg_y
= int( ((HEIGHT
- top_pos
)/(HEIGHT
))*(HEIGHT
*(3/4)) + top_pos
- (font2_size
/2) )
130 maxMsg_x
= int( WIDTH
*(3/100) )
131 durMsg_x
= int( WIDTH
*(3/100) )
132 minMsg_x
= int( WIDTH
*(3/100) )
133 draw
.text((maxMsg_x
, maxMsg_y
), maxMsg
, font
=font2
, fill
=(0, 0, 0))
134 draw
.text((durMsg_x
, durMsg_y
), durMsg
, font
=font2
, fill
=(0, 0, 0))
135 draw
.text((minMsg_x
, minMsg_y
), minMsg
, font
=font2
, fill
=(0, 0, 0))
139 # Get the temperature of the CPU for compensation
140 def get_cpu_temperature():
141 process
= Popen(['vcgencmd', 'measure_temp'], stdout
=PIPE
, universal_newlines
=True)
142 output
, _error
= process
.communicate()
143 return float(output
[output
.index('=') + 1:output
.rindex("'")])
145 def rel_to_abs(T
,P
,RH
):
146 """Returns absolute humidity given relative humidity.
151 Absolute temperature in units Kelvin (K).
153 Total pressure in units Pascals (Pa).
155 Relative humidity in units percent (%).
159 absolute_humidity : float
160 Absolute humidity in units [kg water vapor / kg dry air].
164 1. Sonntag, D. "Advancements in the field of hygrometry". 1994. https://doi.org/10.1127/metz/3/1994/51
165 2. Green, D. "Perry's Chemical Engineers' Handbook" (8th Edition). Page "12-4". McGraw-Hill Professional Publishing. 2007.
168 Author: Steven Baltakatei Sandoval
180 # print('DEBUG:Input Temperature (K) :' + str(T));
181 # print('DEBUG:Input Pressure (Pa) :' + str(P));
182 # print('DEBUG:Input Rel. Humidity (%) :' + str(RH));
184 # Set constants and initial conversions
185 epsilon
= 0.62198 # (molar mass of water vapor) / (molar mass of dry air)
186 t
= T
- 273.15; # Celsius from Kelvin
187 P_hpa
= P
/ 100; # hectoPascals (hPa) from Pascals (Pa)
189 # Calculate e_w(T), saturation vapor pressure of water in a pure phase, in Pascals
190 ln_e_w
= -6096*T
**-1 + 21.2409642 - 2.711193*10**-2*T
+ 1.673952*10**-5*T
**2 + 2.433502*math
.log(T
); # Sonntag-1994 eq 7; e_w in Pascals
191 e_w
= math
.exp(ln_e_w
);
192 e_w_hpa
= e_w
/ 100; # also save e_w in hectoPascals (hPa)
193 # print('DEBUG:ln_e_w:' + str(ln_e_w)); # debug
194 # print('DEBUG:e_w:' + str(e_w)); # debug
196 # Calculate f_w(P,T), enhancement factor for water
197 f_w
= 1 + (10**-4*e_w_hpa
)/(273 + t
)*(((38 + 173*math
.exp(-t
/43))*(1 - (e_w_hpa
/ P_hpa
))) + ((6.39 + 4.28*math
.exp(-t
/ 107))*((P_hpa
/ e_w_hpa
) - 1))); # Sonntag-1994 eq 22.
198 # print('DEBUG:f_w:' + str(f_w)); # debug
200 # Calculate e_prime_w(P,T), saturation vapor pressure of water in air-water mixture, in Pascals
201 e_prime_w
= f_w
* e_w
; # Sonntag-1994 eq 18
202 # print('DEBUG:e_prime_w:' + str(e_prime_w)); # debug
204 # Calculate e_prime, vapor pressure of water in air, in Pascals
205 e_prime
= (RH
/ 100) * e_prime_w
;
206 # print('DEBUG:e_prime:' + str(e_prime)); # debug
208 # Calculate r, the absolute humidity, in [kg water vapor / kg dry air]
209 r
= (epsilon
* e_prime
) / (P
- e_prime
);
210 # print('DEBUG:r:' + str(r)); # debug
214 def rel_to_dpt(T
,P
,RH
):
215 """Returns dew point temperature given relative humidity.
220 Absolute temperature in units Kelvin (K).
222 Total pressure in units Pascals (Pa).
224 Relative humidity in units percent (%).
229 Dew point temperature in units Kelvin (K).
233 1. Sonntag, D. "Advancements in the field of hygrometry". 1994. https://doi.org/10.1127/metz/3/1994/51
234 2. Green, D. "Perry's Chemical Engineers' Handbook" (8th Edition). Page "12-4". McGraw-Hill Professional Publishing. 2007.
237 Author: Steven Baltakatei Sandoval
249 # print('DEBUG:Input Temperature (K) :' + str(T));
250 # print('DEBUG:Input Pressure (Pa) :' + str(P));
251 # print('DEBUG:Input Rel. Humidity (%) :' + str(RH));
253 # Set constants and initial conversions
254 epsilon
= 0.62198 # (molar mass of water vapor) / (molar mass of dry air)
255 t
= T
- 273.15; # Celsius from Kelvin
256 P_hpa
= P
/ 100; # hectoPascals (hPa) from Pascals (Pa)
258 # Calculate e_w(T), saturation vapor pressure of water in a pure phase, in Pascals
259 ln_e_w
= -6096*T
**-1 + 21.2409642 - 2.711193*10**-2*T
+ 1.673952*10**-5*T
**2 + 2.433502*math
.log(T
); # Sonntag-1994 eq 7; e_w in Pascals
260 e_w
= math
.exp(ln_e_w
);
261 e_w_hpa
= e_w
/ 100; # also save e_w in hectoPascals (hPa)
262 # print('DEBUG:ln_e_w:' + str(ln_e_w)); # debug
263 # print('DEBUG:e_w:' + str(e_w)); # debug
265 # Calculate f_w(P,T), enhancement factor for water
266 f_w
= 1 + (10**-4*e_w_hpa
)/(273 + t
)*(((38 + 173*math
.exp(-t
/43))*(1 - (e_w_hpa
/ P_hpa
))) + ((6.39 + 4.28*math
.exp(-t
/ 107))*((P_hpa
/ e_w_hpa
) - 1))); # Sonntag-1994 eq 22.
267 # print('DEBUG:f_w:' + str(f_w)); # debug
269 # Calculate e_prime_w(P,T), saturation vapor pressure of water in air-water mixture, in Pascals
270 e_prime_w
= f_w
* e_w
; # Sonntag-1994 eq 18
271 # print('DEBUG:e_prime_w:' + str(e_prime_w)); # debug
273 # Calculate e_prime, vapor pressure of water in air, in Pascals
274 e_prime
= (RH
/ 100) * e_prime_w
;
275 # print('DEBUG:e_prime:' + str(e_prime)); # debug
277 n
= 0; repeat_flag
= True;
278 while repeat_flag
== True:
279 # print('DEBUG:n:' + str(n)); # debug
281 # Calculate f_w_td, the enhancement factor for water at dew point temperature.
283 f
= 1.0016 + 3.15*10**-6*P_hpa
- (0.074 / P_hpa
); # Sonntag-1994 eq 24
284 f_w_td
= f
; # initial approximation
286 t_d_prev
= float(t_d
); # save previous t_d value for later comparison
287 f_w_td
= 1 + (10**-4*e_w_hpa
)/(273 + t_d
)*(((38 + 173*math
.exp(-t_d
/43))*(1 - (e_w_hpa
/ P_hpa
))) + ((6.39 + 4.28*math
.exp(-t_d
/ 107))*((P_hpa
/ e_w_hpa
) - 1))); # Sonntag-1994 eq 22.
288 # print('DEBUG:f_w_td:' + str(f_w_td)); # debug
290 # Calculate e, the vapor pressure of water in the pure phase, in Pascals
291 e
= (e_prime
/ f_w_td
); # Sonntag-1994 eq 9 and 20
292 # print('DEBUG:e:' + str(e)); # debug
294 # Calculate y, an intermediate dew point calculation variable
295 y
= math
.log(e
/ 611.213);
296 # print('DEBUG:y:' + str(y)); # debug
298 # Calculate t_d, the dew point temperature in degrees Celsius
299 t_d
= 13.715*y
+ 8.4262*10**-1*y
**2 + 1.9048*10**-2*y
**3 + 7.8158*10**-3*y
**4;# Sonntag-1994 eq 10
300 # print('DEBUG:t_d:' + str(t_d)); # debug
307 t_d_diff
= math
.fabs(t_d
- t_d_prev
);
308 # print('DEBUG:t_d :' + str(t_d)); # debug
309 # print('DEBUG:t_d_prev:' + str(t_d_prev)); # debug
310 # print('DEBUG:t_d_diff:' + str(t_d_diff)); # debug
316 # Calculate T_d, the dew point temperature in Kelvin
318 # print('DEBUG:T_d:' + str(T_d)); # debug
321 return T_d
; # good enough
323 # update loop counter
327 # Tuning factor for compensation. Decrease this number to adjust the
328 # temperature down, and increase to adjust up
331 cpu_temps
= [get_cpu_temperature()] * 5
333 delay
= 0.5 # Debounce the proximity tap
334 mode
= 0 # The starting mode
338 # Create a values dict to store the data
339 variables
= ["temperature",
343 "dewpoint_temperature",
345 values
= {} # Initialize values dictionary
347 values
[v
] = [1] * WIDTH
# Init a WIDTH-length list as value for each string in variables
349 # Create a varLenBuffer dict to store recent data
352 varLenBuffer
[v
] = [] # Init an empty list for each string in variables
354 # Create a varLenBufferFlt dict to store recent data as floats only
357 varLenBufferFlt
[v
] = [] # Init an empty list for each string in variables
359 # Create a fixLenBuffer dict to store data for displaying
362 fixLenBuffer
[v
] = [] # Init an empty list for each string in variables
367 # Desc: Update variables containing latest sensor tuples
368 # Output: (time [ns], unit, float)
369 # now_temp_tuple (°C)
370 # now_pressure_tuple (hPa)
371 # now_humidity_tuple (%)
372 # now_humidity_abs_gkg_tuple (g water vapor / kg dry air)
373 # now_illuminance_tuple (lux)
374 # Depends: time, bme280, ltr559, get_cpu_temperature(), rel_to_abs(), rel_to_dpt()
376 # Tell function to modify these global variables
377 global now_temp_tuple
378 global now_pressure_tuple
379 global now_humidity_tuple
380 global now_humidity_abs_gkg_tuple
381 global now_humidity_dpt_c_tuple
382 global now_illuminance_tuple
385 poll_time_ns_start
= time
.time_ns() # Get time reading (unix spoech, nanoseconds)
386 # Get temperature reading
387 cpu_temp
= get_cpu_temperature() # get °C from CPU
388 # Smooth out with some averaging to decrease jitter
389 cpu_temps
= cpu_temps
[1:] + [cpu_temp
]
390 avg_cpu_temp
= sum(cpu_temps
) / float(len(cpu_temps
))
391 raw_temp
= bme280
.get_temperature() # get °C from BME280 sensor
392 now_temp
= raw_temp
- ((avg_cpu_temp
- raw_temp
) / factor
)
393 now_temp_tuple
= (time
.time_ns(), '°C', now_temp
)
394 # Get pressure reading
395 now_time_ns
= time
.time_ns() # Get time reading (unix epoch, nanoseconds)
396 now_pressure
= bme280
.get_pressure() # get hPa from BME280 sensor
397 now_pressure_tuple
= (time
.time_ns(), 'hPa', now_pressure
)
398 # Get relative humidity reading
399 now_humidity
= bme280
.get_humidity() # get % relative humidity from BME280 sensor
400 now_humidity_tuple
= (time
.time_ns(), '%', now_humidity
)
401 # Calculate absolute humidity reading
402 raw_temp_k
= 273.15 + raw_temp
; # convert sensor temp from degC to K
403 now_pressure_pa
= now_pressure
* 100; # convert sensor pressure from hPa to Pa
404 now_humidity_abs
= rel_to_abs(raw_temp_k
, now_pressure_pa
, now_humidity
); # calc kg/kg abs humidity
405 now_humidity_abs_gkg
= now_humidity_abs
* 1000;
406 now_humidity_abs_gkg_tuple
= (time
.time_ns(), 'g/kg', now_humidity_abs_gkg
);
407 # Calculate dew point temperature
408 now_humidity_dpt
= rel_to_dpt(raw_temp_k
, now_pressure_pa
, now_humidity
); # calc K dpt
409 now_humidity_dpt_c
= now_humidity_dpt
- 273.15;
410 now_humidity_dpt_c_tuple
= (time
.time_ns(), '°C', now_humidity_dpt_c
);
412 proximity
= ltr559
.get_proximity() # get proximity reading
414 now_illuminance
= ltr559
.get_lux() # get lux reading from LTR-559 sensor if nothing is nearby
415 now_illuminance_tuple
= (time
.time_ns(), 'lux', now_illuminance
)
416 poll_time_ns_end
= time
.time_ns()
417 #print('DEBUG:poll time (s):' + str((poll_time_ns_end - poll_time_ns_start)/1000000000))
420 def dateIso8601Str():
421 nowUTC
= datetime
.datetime
.utcnow().replace(tzinfo
=datetime
.timezone
.utc
).isoformat()
424 def medianSubset(listIn
: list = [], listOutLen
: int = 0) -> list:
425 # Input: int: listOutLen: quantity of elements in output list
426 # list: listIn: input list consisting of integers or floats
427 # Output: list: ints/floats of specified size
428 # Ref/Attrib: PEP 3107 typing https://stackoverflow.com/a/21384492
430 #print('DEBUG:listOutLen:' + str(listOutLen))
431 #print('DEBUG:listIn:' + str(listIn))
433 # Exit for invalid input
434 if not isinstance(listOutLen
, int):
435 raise ValueError('ERROR:Not a valid int:' + str(listOutLen
))
437 if not listOutLen
> 0:
438 raise ValueError('ERROR:Invalid value:' + str(listOutLen
))
439 if not isinstance(listIn
, list):
440 raise ValueError('ERROR:Not a valid list:' + str(listOutLen
))
441 if not all([( (isinstance(x
,int)) or (isinstance(x
,float)) ) for x
in listIn
]):
442 raise ValueError('ERROR:Input list contains something besides integers or floating point numbers.')
445 listOut
= [None] * listOutLen
446 #print('DEBUG:listOut:' + str(listOut))
449 listInLen
= len(listIn
)
450 #print('DEBUG:listInLen:' + str(listInLen))
452 # Calc subset length float
453 subsetLenFloat
= ( (max([listInLen
,listOutLen
]) - 1) /min([listInLen
,listOutLen
]))
454 subsetIndRatio
= ( (listInLen
)/(listOutLen
) )
455 #print('DEBUG:subsetLenFloat: %.5f' % subsetLenFloat)
456 #print('DEBUG:subsetLenFloat2: %.5f' % subsetIndRatio)
458 # Iterate for each element in listOut
459 for i_out
in range(listOutLen
):
460 #print('DEBUG:i_out:' + str(i_out))
461 ## Decide to expand or reduce listIn to produce listOut
462 if listInLen
> listOutLen
:
463 ### reduce listIn to listOut
464 #print('DEBUG:listOutLen:' + str(listOutLen))
465 #print('DEBUG:listInLen:' + str(listInLen))
467 #### Initialize subsetIndLo in first loop
469 #print('DEBUG:subsetIndLo:' + str(subsetIndLo))
470 #print('DEBUG:i_out:' + str(i_out))
471 #### Calc indices of i_out'th subset of listIn
472 subsetIndHi
= (listInLen
- 1) * (i_out
+ 1) // listOutLen
473 subsetLen
= subsetIndHi
- subsetIndLo
+ 1
474 #print('DEBUG:subsetIndLo:' + str(subsetIndLo))
475 #print('DEBUG:subsetIndHi:' + str(subsetIndHi))
476 #print('DEBUG:subsetLen:' + str(subsetLen))
477 #### Extract subset from listIn using indices inclusively
478 subset
= listIn
[ int(subsetIndLo
) : int(subsetIndHi
)+1 ]
479 #print('DEBUG:subset:' + str(subset))
480 #### Calculate median for subset
481 subsetMedian
= np
.median(subset
)
482 #print('DEBUG:subset median:' + str(subsetMedian))
483 #### Set listOut element
484 listOut
[i_out
] = subsetMedian
486 ##### Update subsetIndLo for next loop
487 subsetIndLo
= subsetIndHi
+ 1
488 #print('DEBUG:Updated subsetIndLo:' + str(subsetIndLo))
489 elif listOutLen
> listInLen
:
490 ### Expand listIn to listOut
491 #print('DEBUG:listOutLen:' + str(listOutLen))
492 #print('DEBUG:listInLen:' + str(listInLen))
493 #### Identify index list of lists mapping listIn to ListOut
494 expandIndex
= int(i_out
/ subsetLenFloat
)
495 expandIndex
= min([expandIndex
,(listInLen
- 1)])
496 #print('DEBUG:expandIndex:' + str(expandIndex))
497 listOut
[i_out
] = listIn
[expandIndex
]
498 #print('DEBUG:listOut[i_out]:' + str(listOut[i_out]))
499 elif listOutLen
== listInLen
:
501 #print('DEBUG:end for loop===========')
505 global now_temp_tuple
506 global now_pressure_tuple
507 global now_humidity_tuple
508 global now_humidity_abs_gkg_tuple
509 global now_humidity_dpt_c_tuple
510 global now_illuminance_tuple
513 global fixLenBufferFlt
515 #print('DEBUG:This is the updateBuffer() function.')
516 #print('DEBUG:===========================================================')
517 #print('DEBUG:===========================================================')
518 # Capture new sensor tuples
520 #print('DEBUG:now_temp_tuple:' + str(now_temp_tuple))
521 #print('DEBUG:now_pressure_tuple:' + str(now_pressure_tuple))
522 #print('DEBUG:now_humidity_tuple:' + str(now_humidity_tuple))
523 #print('DEBUG:now_humidity_abs_gkg_tuple:' + str(now_humidity_abs_gkg_tuple))
524 #print('DEBUG:now_humidity_dpt_c_tuple:' + str(now_humidity_dpt_c_tuple))
525 #print('DEBUG:now_illuminance_tuple:' + str(now_illuminance_tuple))
527 # Append new sensor tuples to varying-length buffer
529 varLenBuffer
[variables
[0]].append(now_temp_tuple
)
531 varLenBuffer
[variables
[1]].append(now_pressure_tuple
)
533 varLenBuffer
[variables
[2]].append(now_humidity_tuple
)
535 varLenBuffer
[variables
[3]].append(now_humidity_abs_gkg_tuple
)
536 ## Dew Point Temperature
537 varLenBuffer
[variables
[4]].append(now_humidity_dpt_c_tuple
)
539 varLenBuffer
[variables
[5]].append(now_illuminance_tuple
)
540 #print('DEBUG:varLenBuffer:' + str(varLenBuffer))
542 # Trim outdated sensor tuples from varying-length buffer
543 ## iterate through each tuple list and remove old tuples
544 varLenBufferTemp
= []
546 #varLenBufferTemp = varLenBuffer[v].copy()
547 now_time_ns
= time
.time_ns() # get ns timestamp of now
548 thn_time_ns
= varLenBuffer
[v
][0][0] # get ns timestamp of earliest tuple
549 dif_time_ns
= now_time_ns
- thn_time_ns
# calc nanosecond difference
550 #print('DEBUG:varLenBufferTTL:' + str(varLenBufferTTL))
551 #print('DEBUG:now:' + str(now_time_ns))
552 #print('DEBUG:thn:' + str(thn_time_ns))
553 #print('DEBUG:dif:' + str(dif_time_ns))
554 #print('DEBUG:dif(s):' + str(dif_time_ns / 1000000000))
555 if dif_time_ns
> varLenBufferTTL
:
556 varLenBuffer
[v
].pop(0) # discard earliest tuple if age > varLenBufferTTL
557 print('DEBUG:Len of varLenBuffer[' + str(v
) + ']:' + str(len(varLenBuffer
[v
])))
558 #print('DEBUG:*******************************************')
559 #print('DEBUG:varLenBuffer[variables[' + str(v) + ']]:' + str(varLenBuffer[v]))
560 #print('DEBUG:*******************************************')
562 # Calculate buffer time span in hours
563 ## Get earliest timestamp (use temperature tuples)
564 first_time_ns
= varLenBuffer
[variables
[0]][0][0]
565 last_time_ns
= varLenBuffer
[variables
[0]][-1][0]
566 span_time_ns
= int(last_time_ns
- first_time_ns
)
567 span_time_h
= float(span_time_ns
/ (10**9*60*60)) # nanoseconds to hours
569 # Convert tuple buffer into float buffer
571 varLenBufferFlt
[v
].clear() # clear old float list
572 #print('DEBUG:v:' + str(v))
573 for t
in varLenBuffer
[v
]:
574 #print('DEBUG:t:' + str(t))
575 #print('DEBUG:t[2]:' + str(t[2]))
576 #print('DEBUG:------------------------------------------')
577 #print('DEBUG:varLenBufferFlt[' + str(v) + ']:' + str(varLenBufferFlt[v]))
578 #print('DEBUG:------------------------------------------')
579 if isinstance(t
[2], float):
580 varLenBufferFlt
[v
].append(float(t
[2])) # build new float list
582 varLenBufferFlt
[v
].append(float(-273)) # add obvious zero otherwise
583 #print('DEBUG:varLenBufferFlt[' + str(v) + ']:' + str(varLenBufferFlt[v]))
585 # Compress/expand buffer to fixed-length buffer
587 #print('DEBUG:varLenBufferFlt[0]:' + str(varLenBufferFlt[variables[0]]))
588 fixLenBuffer
[v
] = medianSubset(varLenBufferFlt
[v
], WIDTH
)
589 print('DEBUG:Len of fixLenBuffer[' + str(v
) + ']:' + str(len(fixLenBuffer
[v
])))
590 #print('DEBUG:fixLenBuffer[' + str(v) + ']:' + str(fixLenBuffer[v]))
596 # schedule.every(1).second.do(updateBuffer)
597 schedule
.every().minute
.at(":00").do(updateBuffer
)
598 # schedule.every().minute.at(":05").do(updateBuffer)
599 # schedule.every().minute.at(":10").do(updateBuffer)
600 # schedule.every().minute.at(":15").do(updateBuffer)
601 # schedule.every().minute.at(":20").do(updateBuffer)
602 # schedule.every().minute.at(":25").do(updateBuffer)
603 # schedule.every().minute.at(":30").do(updateBuffer)
604 # schedule.every().minute.at(":35").do(updateBuffer)
605 # schedule.every().minute.at(":40").do(updateBuffer)
606 # schedule.every().minute.at(":45").do(updateBuffer)
607 # schedule.every().minute.at(":50").do(updateBuffer)
608 # schedule.every().minute.at(":55").do(updateBuffer)
609 pollSensors() # initial run to start up sensors
610 time
.sleep(1) # pause to give sensors time to initialize
611 updateBuffer() # initial run
614 proximity
= ltr559
.get_proximity()
616 # If the proximity crosses the threshold, toggle the display mode
617 if proximity
> 1500 and time
.time() - last_page
> delay
:
619 mode
%= len(variables
)
620 last_page
= time
.time()
622 # Run scheduled tasks
623 schedule
.run_pending()
625 # One display mode for each variable
627 # variable = "temperature"
628 ## run function to display latest temp values in variables[mode] list
630 cpu_temp
= get_cpu_temperature()
631 # Smooth out with some averaging to decrease jitter
632 cpu_temps
= cpu_temps
[1:] + [cpu_temp
]
633 avg_cpu_temp
= sum(cpu_temps
) / float(len(cpu_temps
))
634 raw_temp
= bme280
.get_temperature()
635 data
= raw_temp
- ((avg_cpu_temp
- raw_temp
) / factor
)
636 #display_text(variables[mode], data, unit)
637 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
640 # variable = "pressure"
642 data
= bme280
.get_pressure()
643 #display_text(variables[mode], data, unit)
644 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
647 # variable = "humidity"
649 data
= bme280
.get_humidity()
650 #display_text(variables[mode], data, unit)
651 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
654 # variable = "humidity_abs"
656 raw_temp
= bme280
.get_temperature() # get °C from BME280 sensor
657 raw_temp_k
= 273.15 + raw_temp
; # convert sensor temp from degC to K
658 now_pressure
= bme280
.get_pressure() # get hPa from BME280 sensor
659 now_pressure_pa
= now_pressure
* 100; # convert sensor pressure from hPa to Pa
660 now_humidity
= bme280
.get_humidity() # get % relative humidity from BME280 sensor
661 now_humidity_abs
= rel_to_abs(raw_temp_k
,now_pressure_pa
,now_humidity
); # calc [kg water / kg dry air] abs humidity
662 now_humidity_abs_gkg
= now_humidity_abs
* 1000; # convert kg/kg to g/kg abs humidity
663 data
= now_humidity_abs_gkg
;
664 # print('DEBUG:raw_temp:' + str(raw_temp));
665 # print('DEBUG:raw_temp_k:' + str(raw_temp_k));
666 # print('DEBUG:now_pressure:' + str(now_pressure));
667 # print('DEBUG:now_pressure_pa:' + str(now_pressure_pa));
668 # print('DEBUG:now_humidity:' + str(now_humidity));
669 # print('DEBUG:now_humidity_abs_gkg:' + str(now_humidity_abs_gkg));
670 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
673 # variable = "humidity_abs"
675 raw_temp
= bme280
.get_temperature() # get °C from BME280 sensor
676 raw_temp_k
= 273.15 + raw_temp
; # convert sensor temp from degC to K
677 now_pressure
= bme280
.get_pressure() # get hPa from BME280 sensor
678 now_pressure_pa
= now_pressure
* 100; # convert sensor pressure from hPa to Pa
679 now_humidity
= bme280
.get_humidity() # get % relative humidity from BME280 sensor
680 now_humidity_dpt
= rel_to_dpt(raw_temp_k
,now_pressure_pa
,now_humidity
); # calc K dpt humidity
681 now_humidity_dpt_c
= now_humidity_dpt
- 273.15; # convert K to °C dpt humidity
682 data
= now_humidity_dpt_c
;
683 # print('DEBUG:raw_temp:' + str(raw_temp));
684 # print('DEBUG:raw_temp_k:' + str(raw_temp_k));
685 # print('DEBUG:now_pressure:' + str(now_pressure));
686 # print('DEBUG:now_pressure_pa:' + str(now_pressure_pa));
687 # print('DEBUG:now_humidity:' + str(now_humidity));
688 # print('DEBUG:now_humidity_dpt_c:' + str(now_humidity_dpt_c));
689 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
695 data
= ltr559
.get_lux()
698 #display_text(variables[mode], data, unit)
699 display_text2(variables
[mode
],data
,unit
,fixLenBuffer
)
704 except KeyboardInterrupt: