1+ /* !
2+ * @file drvMlx90632.h
3+ *
4+ * Device driver for the Melexis MLX90632 Far Infrared temp sensor
5+ *
6+ * Adafruit invests time and resources providing this open source code,
7+ * please support Adafruit and open-source hardware by purchasing
8+ * products from Adafruit!
9+ *
10+ * Copyright (c) Tyeth Gundry 2025 for Adafruit Industries.
11+ *
12+ * MIT license, all text here must be included in any redistribution.
13+ *
14+ */
15+ #ifndef DRV_MLX90632_H
16+ #define DRV_MLX90632_H
17+
18+ #include " drvBase.h"
19+ #include < Adafruit_MLX90632.h>
20+
21+ /* !
22+ @brief Class that provides a driver interface for an MLX90632 sensor.
23+ */
24+ class drvMLX90632 : public drvBase {
25+ public:
26+ /* ******************************************************************************/
27+ /* !
28+ @brief Constructor for an MLX90632 sensor.
29+ @param i2c
30+ The I2C interface.
31+ @param sensorAddress
32+ The 7-bit I2C address of the sensor.
33+ @param mux_channel
34+ The I2C multiplexer channel.
35+ @param driver_name
36+ The name of the driver.
37+ */
38+ /* ******************************************************************************/
39+ drvMLX90632 (TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel,
40+ const char *driver_name)
41+ : drvBase(i2c, sensorAddress, mux_channel, driver_name) {
42+ _mlx90632 = nullptr ;
43+ _deviceTemp = NAN;
44+ _objectTemp = NAN;
45+ _lastRead = 0 ;
46+ }
47+
48+ /* ******************************************************************************/
49+ /* !
50+ @brief Destructor for an MLX90632 sensor.
51+ */
52+ /* ******************************************************************************/
53+ ~drvMLX90632 () {
54+ if (_mlx90632) {
55+ delete _mlx90632;
56+ _mlx90632 = nullptr ;
57+ }
58+ }
59+
60+ /* ******************************************************************************/
61+ /* !
62+ @brief Initializes the MLX90632 sensor and begins I2C.
63+ @returns True if initialized successfully, False otherwise.
64+ */
65+ /* ******************************************************************************/
66+ bool begin () override {
67+ if (_mlx90632) {
68+ delete _mlx90632;
69+ _mlx90632 = nullptr ;
70+ }
71+ _mlx90632 = new Adafruit_MLX90632 ();
72+ if (!_mlx90632->begin (_address, _i2c)) {
73+ return false ;
74+ }
75+
76+ return ConfigureAndPrintSensorInfo ();
77+ }
78+
79+ /* ******************************************************************************/
80+ /* !
81+ @brief Configures the MLX90632 sensor and prints its information.
82+ @param extendedInsteadOfMedicalRange
83+ If true, configures the sensor for extended temperature
84+ range/acc.
85+ @returns True if configuration fetching and setting were successful.
86+ */
87+ /* ******************************************************************************/
88+ bool ConfigureAndPrintSensorInfo (bool extendedInsteadOfMedicalRange = false ) {
89+ // Reset the device
90+ if (!_mlx90632->reset ()) {
91+ WS_DEBUG_PRINTLN (F (" Device reset failed" ));
92+ return false ;
93+ }
94+
95+ uint16_t productCode = _mlx90632->getProductCode ();
96+ // Decode product code bits
97+ uint8_t accuracy = productCode & 0x1F ;
98+
99+ if (!_mlx90632->setMode (MLX90632_MODE_CONTINUOUS)) {
100+ WS_DEBUG_PRINTLN (F (" Failed to set mode" ));
101+ return false ;
102+ }
103+
104+ // set accuracy mode based on medical if detected
105+ if (accuracy == 1 ) {
106+ // Set and get measurement select (medical)
107+ if (!extendedInsteadOfMedicalRange &&
108+ !_mlx90632->setMeasurementSelect (MLX90632_MEAS_MEDICAL)) {
109+ WS_DEBUG_PRINTLN (F (" Failed to set measurement select to Medical" ));
110+ return false ;
111+ } else if (extendedInsteadOfMedicalRange &&
112+ !_mlx90632->setMeasurementSelect (
113+ MLX90632_MEAS_EXTENDED_RANGE)) {
114+ WS_DEBUG_PRINTLN (
115+ F (" Failed to set measurement select to Extended Range" ));
116+ return false ;
117+ }
118+ }
119+
120+ // Set and get refresh rate (default to 2Hz)
121+ if (!_mlx90632->setRefreshRate (MLX90632_REFRESH_2HZ)) {
122+ WS_DEBUG_PRINTLN (F (" Failed to set refresh rate to 2Hz" ));
123+ return false ;
124+ }
125+
126+ if (!_mlx90632->resetNewData ()) {
127+ WS_DEBUG_PRINTLN (F (" Failed to reset new data flag" ));
128+ return false ;
129+ }
130+ return true ;
131+ }
132+
133+ /* ******************************************************************************/
134+ /* !
135+ @brief Checks if sensor was read within last 1s, or is the first read.
136+ @returns True if the sensor was recently read, False otherwise.
137+ */
138+ /* ******************************************************************************/
139+ bool HasBeenReadInLast200ms () {
140+ return _lastRead != 0 && millis () - _lastRead < 200 ;
141+ }
142+
143+ /* ******************************************************************************/
144+ /* !
145+ @brief Reads the sensor.
146+ @returns True if the sensor was read successfully, False otherwise.
147+ */
148+ /* ******************************************************************************/
149+ bool ReadSensorData () {
150+ bool result = false ;
151+ if (HasBeenReadInLast200ms ()) {
152+ WS_DEBUG_PRINTLN (F (" Sensor was read recently, using cached data" ));
153+ return true ;
154+ }
155+
156+ // Check if we need to trigger a new measurement for step modes
157+ mlx90632_mode_t currentMode = _mlx90632->getMode ();
158+ if (currentMode == MLX90632_MODE_STEP ||
159+ currentMode == MLX90632_MODE_SLEEPING_STEP) {
160+ // Trigger single measurement (SOC bit) for step modes
161+ if (!_mlx90632->startSingleMeasurement ()) {
162+ WS_DEBUG_PRINTLN (F (" Failed to start single measurement" ));
163+ return false ;
164+ }
165+ delay (510 ); // Wait for measurement to complete @ 2Hz
166+ }
167+
168+ // Only check new data flag - much more efficient for continuous mode
169+ if (_mlx90632->isNewData ()) {
170+ _deviceTemp = _mlx90632->getAmbientTemperature ();
171+ _objectTemp = _mlx90632->getObjectTemperature ();
172+ if (isnan (_objectTemp)) {
173+ WS_DEBUG_PRINTLN (F (" NaN (invalid cycle position)" ));
174+ return false ;
175+ }
176+ result = true ;
177+ _lastRead = millis ();
178+ // Reset new data flag after reading
179+ if (!_mlx90632->resetNewData ()) {
180+ WS_DEBUG_PRINTLN (F (" Failed to reset new data flag" ));
181+ }
182+ } else {
183+ WS_DEBUG_PRINTLN (F (" No new data available, skipping read" ));
184+ }
185+
186+ return result;
187+ }
188+
189+ /* ******************************************************************************/
190+ /* !
191+ @brief Gets the MLX90632's current temperature.
192+ @param tempEvent
193+ Pointer to an Adafruit_Sensor event.
194+ @returns True if the temperature was obtained successfully, False
195+ otherwise.
196+ */
197+ /* ******************************************************************************/
198+ bool getEventAmbientTemp (sensors_event_t *tempEvent) {
199+ if (ReadSensorData () && _deviceTemp != NAN) {
200+ tempEvent->temperature = _deviceTemp;
201+ return true ;
202+ }
203+ return false ; // sensor not read recently, return false
204+ }
205+
206+ /* ******************************************************************************/
207+ /* !
208+ @brief Gets the MLX90632's object temperature.
209+ @param tempEvent
210+ Pointer to an Adafruit_Sensor event.
211+ @returns True if the temperature was obtained successfully, False
212+ otherwise.
213+ */
214+ /* ******************************************************************************/
215+ bool getEventObjectTemp (sensors_event_t *tempEvent) {
216+ if (ReadSensorData () && _objectTemp != NAN) {
217+ tempEvent->temperature = _objectTemp;
218+ return true ;
219+ }
220+ return false ; // sensor not read recently, return false
221+ }
222+
223+ void ConfigureDefaultSensorTypes () override {
224+ _default_sensor_types_count = 4 ;
225+ _default_sensor_types[0 ] =
226+ wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE;
227+ _default_sensor_types[1 ] =
228+ wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE;
229+ _default_sensor_types[2 ] =
230+ wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE_FAHRENHEIT;
231+ _default_sensor_types[3 ] =
232+ wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE_FAHRENHEIT;
233+ }
234+
235+ protected:
236+ double _deviceTemp; // /< Device temperature in Celsius
237+ double _objectTemp; // /< Object temperature in Celsius
238+ uint32_t _lastRead; // /< Last time the sensor was read in milliseconds
239+ Adafruit_MLX90632 *_mlx90632; // /< Pointer to MLX90632 sensor object
240+ };
241+
242+ #endif // drvMLX90632
0 commit comments