Expand test coverage, bugfix
[EVA-2020-02-2.git] / library / enviroplus / gas.py
1 """Read the MICS6814 via an ads1015 ADC"""
2
3 import time
4 import atexit
5 import ads1015
6 import RPi.GPIO as GPIO
7
8 MICS6814_HEATER_PIN = 24
9 MICS6814_GAIN = 6.144
10
11 ads1015.I2C_ADDRESS_DEFAULT = ads1015.I2C_ADDRESS_ALTERNATE
12 _is_setup = False
13 _adc_enabled = False
14 _adc_gain = 6.148
15
16
17 class Mics6814Reading(object):
18 __slots__ = 'oxidising', 'reducing', 'nh3', 'adc'
19
20 def __init__(self, ox, red, nh3, adc=None):
21 self.oxidising = ox
22 self.reducing = red
23 self.nh3 = nh3
24 self.adc = adc
25
26 def __repr__(self):
27 fmt = """Oxidising: {ox:05.02f} Ohms
28 Reducing: {red:05.02f} Ohms
29 NH3: {nh3:05.02f} Ohms"""
30 if self.adc is not None:
31 fmt += """
32 ADC: {adc:05.02f} Volts
33 """
34 return fmt.format(
35 ox=self.oxidising,
36 red=self.reducing,
37 nh3=self.nh3,
38 adc=self.adc)
39
40 __str__ = __repr__
41
42
43 def setup():
44 global adc, _is_setup
45 if _is_setup:
46 return
47 _is_setup = True
48
49 adc = ads1015.ADS1015(i2c_addr=0x49)
50 adc.set_mode('single')
51 adc.set_programmable_gain(MICS6814_GAIN)
52 adc.set_sample_rate(1600)
53
54 GPIO.setwarnings(False)
55 GPIO.setmode(GPIO.BCM)
56 GPIO.setup(MICS6814_HEATER_PIN, GPIO.OUT)
57 GPIO.output(MICS6814_HEATER_PIN, 1)
58 atexit.register(cleanup)
59
60
61 def enable_adc(value=True):
62 """Enable reading from the additional ADC pin."""
63 global _adc_enabled
64 _adc_enabled = value
65
66
67 def set_adc_gain(value):
68 """Set gain value for the additional ADC pin."""
69 global _adc_gain
70 _adc_gain = value
71
72
73 def cleanup():
74 GPIO.output(MICS6814_HEATER_PIN, 0)
75
76
77 def read_all():
78 """Return gas resistence for oxidising, reducing and NH3"""
79 setup()
80 ox = adc.get_voltage('in0/gnd')
81 red = adc.get_voltage('in1/gnd')
82 nh3 = adc.get_voltage('in2/gnd')
83
84 try:
85 ox = (ox * 56000) / (3.3 - ox)
86 except ZeroDivisionError:
87 ox = 0
88
89 try:
90 red = (red * 56000) / (3.3 - red)
91 except ZeroDivisionError:
92 red = 0
93
94 try:
95 nh3 = (nh3 * 56000) / (3.3 - nh3)
96 except ZeroDivisionError:
97 nh3 = 0
98
99 analog = None
100
101 if _adc_enabled:
102 if _adc_gain == MICS6814_GAIN:
103 analog = adc.get_voltage('ref/gnd')
104 else:
105 adc.set_programmable_gain(_adc_gain)
106 time.sleep(0.05)
107 analog = adc.get_voltage('ref/gnd')
108 adc.set_programmable_gain(MICS6814_GAIN)
109
110 return Mics6814Reading(ox, red, nh3, analog)
111
112
113 def read_oxidising():
114 """Return gas resistance for oxidising gases.
115
116 Eg chlorine, nitrous oxide
117 """
118 setup()
119 return read_all().oxidising
120
121
122 def read_reducing():
123 """Return gas resistance for reducing gases.
124
125 Eg hydrogen, carbon monoxide
126 """
127 setup()
128 return read_all().reducing
129
130
131 def read_nh3():
132 """Return gas resistance for nh3/ammonia"""
133 setup()
134 return read_all().nh3
135
136
137 def read_adc():
138 """Return spare ADC channel value"""
139 setup()
140 return read_all().adc