1
- /* Flipper App to read the values from a HTU21D Sensor */
1
+ /* Flipper App to read the values from a HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320 Sensor */
2
2
/* Created by Mywk - https://github.com/Mywk - https://mywk.net */
3
3
#include <furi.h>
4
4
#include <furi_hal.h>
14
14
15
15
#define TS_DEFAULT_VALUE 0xFFFF
16
16
17
- #define HTU21D_ADDRESS (0x40 << 1)
17
+ #define TS_AVAILABLE_SENSORS 2
18
18
19
+ // HTU2XD, SHT2X, SI702X, SI700X address
20
+ #define HTU2XD_SHT2X_SI702X_SI700X_ADDRESS (0x40 << 1)
21
+ // SI701X ADDRESS
22
+ #define SI701X_ADDRESS (0x41 << 1)
23
+
24
+ // HTU2XD, SHT2X, SI702X, SI700X commands
19
25
#define HTU21D_CMD_TEMPERATURE 0xE3
20
26
#define HTU21D_CMD_HUMIDITY 0xE5
21
27
28
+ // AM2320 address
29
+ #define AM2320_ADDRESS (0x5C << 1)
30
+
31
+ // Used for the temperature and humidity buffers
22
32
#define DATA_BUFFER_SIZE 8
23
33
24
34
// External I2C BUS
25
35
#define I2C_BUS &furi_hal_i2c_handle_external
26
36
37
+ // Typedef enums to make everything easier to read
38
+
39
+ typedef enum { TSSCmdNone , TSSCmdTemperature , TSSCmdHumidity } TSSCmdType ;
40
+
27
41
typedef enum {
28
42
TSSInitializing ,
29
43
TSSNoSensor ,
@@ -40,11 +54,25 @@ typedef struct {
40
54
InputEvent input ;
41
55
} TSEvent ;
42
56
57
+ // Possible return values for sensor_cmd
58
+ typedef enum {
59
+ TSCmdRet_Error ,
60
+ TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X ,
61
+ TSCmdRet_SI701X ,
62
+ TSCmdRet_AM2320 ,
63
+ } TSCmdRet ;
64
+
65
+ // External NotificationSequence RGB
43
66
extern const NotificationSequence sequence_blink_red_100 ;
67
+ extern const NotificationSequence sequence_blink_green_100 ;
44
68
extern const NotificationSequence sequence_blink_blue_100 ;
45
69
70
+ // Current status of the temperature sensor app
46
71
static TSStatus temperature_sensor_current_status = TSSInitializing ;
47
72
73
+ // We keep track of the last cmd return
74
+ static TSCmdRet temperature_sensor_last_cmd_ret = TSCmdRet_Error ;
75
+
48
76
// Temperature and Humidity data buffers, ready to print
49
77
char ts_data_buffer_temperature_c [DATA_BUFFER_SIZE ];
50
78
char ts_data_buffer_temperature_f [DATA_BUFFER_SIZE ];
@@ -54,46 +82,80 @@ char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE];
54
82
// <sumary>
55
83
// Executes an I2C cmd (trx)
56
84
// </sumary>
85
+ // <TODO>
86
+ // CRC
87
+ // </TODO>
57
88
// <returns>
58
89
// true if fetch was successful, false otherwise
59
90
// </returns>
60
- static bool temperature_sensor_cmd (uint8_t cmd , uint8_t * buffer , uint8_t size ) {
91
+ static TSCmdRet temperature_sensor_cmd (TSSCmdType cmd , uint8_t * buffer ) {
61
92
uint32_t timeout = furi_ms_to_ticks (100 );
62
- bool ret = false ;
93
+ TSCmdRet ret = TSCmdRet_Error ;
63
94
64
95
// Aquire I2C and check if device is ready, then release
65
96
furi_hal_i2c_acquire (I2C_BUS );
66
- if (furi_hal_i2c_is_device_ready (I2C_BUS , HTU21D_ADDRESS , timeout )) {
67
- furi_hal_i2c_release (I2C_BUS );
68
-
69
- furi_hal_i2c_acquire (I2C_BUS );
70
- // Transmit given command
71
- ret = furi_hal_i2c_tx (I2C_BUS , HTU21D_ADDRESS , & cmd , 1 , timeout );
72
- furi_hal_i2c_release (I2C_BUS );
73
-
74
- if (ret ) {
75
- uint32_t wait_ticks = furi_ms_to_ticks (50 );
76
- furi_delay_tick (wait_ticks );
77
-
78
- furi_hal_i2c_acquire (I2C_BUS );
79
- // Receive data
80
- ret = furi_hal_i2c_rx (I2C_BUS , HTU21D_ADDRESS , buffer , size , timeout );
81
- furi_hal_i2c_release (I2C_BUS );
97
+
98
+ // Check if HTU2XD, SHT2X, SI702X, SI700X sensor is available
99
+ uint8_t isAddress40 =
100
+ furi_hal_i2c_is_device_ready (I2C_BUS , HTU2XD_SHT2X_SI702X_SI700X_ADDRESS , timeout );
101
+ uint8_t isAddress41 = 0 ;
102
+
103
+ // Check if SI701X sensor is available if necessary
104
+ if (!isAddress40 ) isAddress41 = furi_hal_i2c_is_device_ready (I2C_BUS , SI701X_ADDRESS , timeout );
105
+
106
+ if (isAddress40 || isAddress41 ) {
107
+ uint8_t address = isAddress40 ? HTU2XD_SHT2X_SI702X_SI700X_ADDRESS : SI701X_ADDRESS ;
108
+
109
+ // Better safe than sorry delay
110
+ furi_delay_ms (15 );
111
+
112
+ // Extra delay for the SI70XX
113
+ if (isAddress41 ) furi_delay_ms (50 );
114
+
115
+ // Transmit either the temperature or the humidity command depending on TSSCmdType
116
+ uint8_t c = (cmd == TSSCmdTemperature ) ? HTU21D_CMD_TEMPERATURE : HTU21D_CMD_HUMIDITY ;
117
+ if (furi_hal_i2c_tx (I2C_BUS , address , & c , 1 , timeout )) {
118
+ // Receive data (2 bytes)
119
+ if (furi_hal_i2c_rx (I2C_BUS , address , buffer , 2 , timeout + 50 ))
120
+ ret = isAddress40 ? TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X : TSCmdRet_SI701X ;
82
121
}
83
122
} else {
84
- furi_hal_i2c_release (I2C_BUS );
123
+ // The AM2320 goes to sleep after a period of inactivity, wake it up (check AM2320 datasheet for more info)
124
+ furi_hal_i2c_is_device_ready (I2C_BUS , AM2320_ADDRESS , timeout );
125
+ furi_delay_ms (30 );
126
+
127
+ // Check if it's really available
128
+ if (furi_hal_i2c_is_device_ready (I2C_BUS , AM2320_ADDRESS , timeout )) {
129
+ // {Address, Register, Len}
130
+ const uint8_t request [3 ] = {0x03 , 0x00 , 0x04 };
131
+
132
+ if (furi_hal_i2c_tx (I2C_BUS , AM2320_ADDRESS , request , 3 , timeout )) {
133
+ // 6 bytes - usually 8 but we currently don't check the CRC
134
+ if (furi_hal_i2c_rx (I2C_BUS , (uint8_t )AM2320_ADDRESS , buffer , 6 , timeout ))
135
+ ret = TSCmdRet_AM2320 ;
136
+ }
137
+ }
85
138
}
86
139
140
+ furi_hal_i2c_release (I2C_BUS );
141
+
142
+ temperature_sensor_last_cmd_ret = ret ;
87
143
return ret ;
88
144
}
89
145
90
146
// <sumary>
91
147
// Fetches temperature and humidity from sensor
92
148
// </sumary>
149
+ // <params>
150
+ // temperature in C
151
+ // humidity in relative humidity
152
+ // </params>
93
153
// <remarks>
94
154
// Temperature and humidity must be preallocated
95
- // Note: CRC is not checked (3rd byte)
96
155
// </remarks>
156
+ // <TODO>
157
+ // CRC
158
+ // </TODO>
97
159
// <returns>
98
160
// true if fetch was successful, false otherwise
99
161
// </returns>
@@ -102,24 +164,36 @@ static bool temperature_sensor_fetch_data(double* temperature, double* humidity)
102
164
103
165
uint16_t adc_raw ;
104
166
105
- uint8_t buffer [2 ] = {0x00 };
106
-
107
- // Fetch temperature
108
- ret = temperature_sensor_cmd ((uint8_t )HTU21D_CMD_TEMPERATURE , buffer , 2 );
167
+ uint8_t buffer [DATA_BUFFER_SIZE ] = {0x00 };
109
168
110
- if (ret ) {
169
+ // Check if the sensor is the HTU21D by attempting to fetch the temperature
170
+ TSCmdRet cmdRet = temperature_sensor_cmd (TSSCmdTemperature , buffer );
171
+ if (cmdRet == TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X || cmdRet == TSCmdRet_SI701X ) {
111
172
// Calculate temperature
112
173
adc_raw = ((uint16_t )(buffer [0 ] << 8 ) | (buffer [1 ]));
113
174
* temperature = (float )(adc_raw * 175.72 / 65536.00 ) - 46.85 ;
114
175
115
176
// Fetch humidity
116
- ret = temperature_sensor_cmd ((uint8_t )HTU21D_CMD_HUMIDITY , buffer , 2 );
117
-
118
- if (ret ) {
177
+ if (temperature_sensor_cmd (TSSCmdHumidity , buffer )) {
119
178
// Calculate humidity
120
179
adc_raw = ((uint16_t )(buffer [0 ] << 8 ) | (buffer [1 ]));
121
180
* humidity = (float )(adc_raw * 125.0 / 65536.00 ) - 6.0 ;
181
+
182
+ ret = true;
122
183
}
184
+ } else if (cmdRet == TSCmdRet_AM2320 ) {
185
+ // The AM2320 returns all the data immediately so we just process it all
186
+ // Note: CRC isn't currently present in the buffer
187
+
188
+ // Temperature
189
+ float temp = (((buffer [4 ] & 0x7F ) << 8 ) + buffer [5 ]) / 10 ;
190
+ * temperature = ((buffer [4 ] & 0x80 ) >> 7 ) == 1 ? temp * (-1 ) : temp ;
191
+
192
+ // Humidity
193
+ temp = ((buffer [2 ] << 8 ) + buffer [3 ]) / 10 ;
194
+ * humidity = temp ;
195
+
196
+ ret = true;
123
197
}
124
198
125
199
return ret ;
@@ -133,7 +207,28 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
133
207
134
208
canvas_clear (canvas );
135
209
canvas_set_font (canvas , FontPrimary );
136
- canvas_draw_str (canvas , 2 , 10 , "HTU21D/Si7021 Sensor" );
210
+
211
+ // Update title accordingly (this could be improved by checking the hardware id)
212
+ switch (temperature_sensor_last_cmd_ret ) {
213
+ case TSCmdRet_Error :
214
+ canvas_draw_str (canvas , 2 , 10 , "Temperature Sensor" );
215
+ break ;
216
+
217
+ case TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X :
218
+ canvas_draw_str (canvas , 2 , 10 , "HTU/SHT/SI70 Sensor" );
219
+ break ;
220
+
221
+ case TSCmdRet_SI701X :
222
+ canvas_draw_str (canvas , 2 , 10 , "SI701X Sensor" );
223
+ break ;
224
+
225
+ case TSCmdRet_AM2320 :
226
+ canvas_draw_str (canvas , 2 , 10 , "AM2320 Sensor" );
227
+ break ;
228
+
229
+ default :
230
+ break ;
231
+ }
137
232
138
233
canvas_set_font (canvas , FontSecondary );
139
234
canvas_draw_str (canvas , 2 , 62 , "Press back to exit." );
@@ -165,7 +260,6 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
165
260
canvas_draw_str (canvas , 100 , 38 , "%" );
166
261
canvas_draw_str (canvas , 68 , 48 , ts_data_buffer_absolute_humidity );
167
262
canvas_draw_str (canvas , 100 , 48 , "g/m3" );
168
-
169
263
} break ;
170
264
default :
171
265
break ;
@@ -199,7 +293,6 @@ static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) {
199
293
int32_t temperature_sensor_app (void * p ) {
200
294
UNUSED (p );
201
295
202
- furi_hal_power_suppress_charge_enter ();
203
296
// Declare our variables and assign variables a default value
204
297
TSEvent tsEvent ;
205
298
bool sensorFound = false;
@@ -236,7 +329,6 @@ int32_t temperature_sensor_app(void* p) {
236
329
if (tsEvent .input .key ==
237
330
InputKeyBack ) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort)
238
331
break ;
239
-
240
332
} else if (tsEvent .type == TSEventTypeTick ) {
241
333
// Update sensor data
242
334
// Fetch data and set the sensor current status accordingly
@@ -270,7 +362,6 @@ int32_t temperature_sensor_app(void* p) {
270
362
snprintf (
271
363
ts_data_buffer_absolute_humidity , DATA_BUFFER_SIZE , "%.2f" , abs_humidity );
272
364
}
273
-
274
365
} else {
275
366
// Reset our variables to their default values
276
367
celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE ;
@@ -280,11 +371,9 @@ int32_t temperature_sensor_app(void* p) {
280
371
}
281
372
}
282
373
283
- uint32_t wait_ticks = furi_ms_to_ticks (!sensorFound ? 100 : 500 );
284
- furi_delay_tick (wait_ticks );
374
+ furi_delay_ms (!sensorFound ? 100 : 500 );
285
375
}
286
376
287
- furi_hal_power_suppress_charge_exit ();
288
377
// Dobby is freee (free our variables, Flipper will crash if we don't do this!)
289
378
furi_timer_free (timer );
290
379
gui_remove_view_port (gui , view_port );
@@ -295,4 +384,4 @@ int32_t temperature_sensor_app(void* p) {
295
384
furi_record_close (RECORD_GUI );
296
385
297
386
return 0 ;
298
- }
387
+ }
0 commit comments