up temp sensor

This commit is contained in:
RogueMaster
2022-11-24 03:41:21 -05:00
parent 34b949ff52
commit 731d3be044
4 changed files with 255 additions and 78 deletions
+2 -1
View File
@@ -22,6 +22,7 @@ Thank you to all the supporters!
- Updated: [Sub-GHz Bruteforcer (By Ganapati & xMasterX)](https://github.com/derskythe/flipperzero-subbrute/tree/master)
- Updated: [Wii EC Analyser (By csBlueChip)](https://github.com/csBlueChip/FlipperZero_WiiEC)
- Updated: [Authenticator/TOTP (By akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
- Updated: [Temperature Sensor (By Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) `Req: HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320`
## Install from Release
FLASH STOCK FIRST BEFORE UPDATING TO CUSTOM FIRMWARE!
@@ -224,7 +225,7 @@ $ ./fbt resources icons dolphin_ext
- [Spectrum Analyzer (By jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) [Updates (for testing) Thanks to theY4Kman](https://github.com/theY4Kman/flipperzero-firmware)
- [Sub-GHz Bruteforcer (By Ganapati & xMasterX)](https://github.com/derskythe/flipperzero-subbrute/tree/master)
- [Sub-GHz Playlist (By darmiel)](https://github.com/darmiel/flipper-playlist)
- [Temperature Sensor (By Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) `Req: HTU21D / SI7021`
- [Temperature Sensor (By Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) `Req: HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320`
- [Temperature Sensor (By xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/commit/9c4612e571db42f5e6123a3f159e01337453a6af) `Req: AM2320`
- [Timelapse (By theageoflove)](https://github.com/theageoflove/flipperzero-zeitraffer)
- [Tuning Fork (By besya)](https://github.com/besya/flipperzero-tuning-fork)
@@ -1,17 +1,65 @@
# Flipper Temperature Sensor - HTU21D / SI7021
[Original link](https://github.com/Mywk/FlipperTemperatureSensor)
# Flipper Temperature Sensor
## Supported sensors
> HTU2xD, SHT2x, SI702x, SI700x, SI701x, AM2320
## What is this?
A small app for the [Flipper Zero](https://flipperzero.one) that reads the [I2C](https://en.wikipedia.org/wiki/I%C2%B2C) signal from a HTU21D or Si7021 sensor and displays the current temperature and humidity.
A small app for the [Flipper Zero](https://flipperzero.one) that reads the [I2C](https://en.wikipedia.org/wiki/I%C2%B2C) signal from a few temperature sensors and displays the current temperature and humidity.
I'm using a [Sparkfun HTU21D sensor](https://learn.sparkfun.com/tutorials/htu21d-humidity-sensor-hookup-guide), also tested with a clone and with the Si7021 variant.
![Flipper Temperature Sensor](docs/Flipper.png)
![Flipper Temperature Sensor](images/Flipper.png)
![App](docs/App.png)
![App](images/App.png)
## How to Connect the sensor
![Connection](docs/Connection.png)
<br/>
# How to Connect the HTU21D sensor
![Connection](images/Connection.png)
# How to install
If you have the FAP loader, just copy the fap file from the Releases into your Flipper apps folder and you should be able to launch it from the menu.
If you don't have the FAP loader you will have to bake this application together with your firmware (aka compile it all together).
# FAQ
## The app says the sensor is not found!
1- Are the four connectors correctly soldered?
2- Are the SCL and SDA connections correct? Re-check the "How to Connect the sensor" above.
3- For the HTU21D, on the sensor board, there should be three contacts in the center, for it to work correctly they must be soldered together (basically drop a blob of solder to connect the three of them). Without the solder it looks like this:
![Sensor](images/Sensor.png)
## Which Flipper versions was this app tested on?
Version 1.2
- RM11221439-0.71.2
- unlshd-015
- 0.71.1
Version 1.1
- RM10302252-0.70.1
- unlshd-012
- 0.68.2-1007-RM
- 0.68.1
- 0.67.2
## I can't build the app together with the firmware?
In the *application.fam*, don't forget to change the apptype, it should not be EXTERNAL but APP.
# How to compile
Place the temperature_sensor folder in the applications_user folder and compile using FBT.
Please refer to the [Flipper Build Tool documentation](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/fbt.md).
@@ -1,6 +1,6 @@
App(
appid="HTU21D_Temperature_Sensor",
name="[HTU21D] Temp Sensor",
appid="Temperature_Sensor",
name="Temperature Sensor",
apptype=FlipperAppType.EXTERNAL,
entry_point="temperature_sensor_app",
cdefines=["APP_TEMPERATURE_SENSOR"],
@@ -1,4 +1,4 @@
/* Flipper App to read the values from a HTU21D Sensor */
/* Flipper App to read the values from a HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320 Sensor */
/* Created by Mywk - https://github.com/Mywk - https://mywk.net */
#include <furi.h>
#include <furi_hal.h>
@@ -14,37 +14,74 @@
#define TS_DEFAULT_VALUE 0xFFFF
#define HTU21D_ADDRESS (0x40 << 1)
#define TS_AVAILABLE_SENSORS 2
// HTU2XD, SHT2X, SI702X, SI700X address
#define HTU2XD_SHT2X_SI702X_SI700X_ADDRESS (0x40 << 1)
// SI701X ADDRESS
#define SI701X_ADDRESS (0x41 << 1)
// HTU2XD, SHT2X, SI702X, SI700X commands
#define HTU21D_CMD_TEMPERATURE 0xE3
#define HTU21D_CMD_HUMIDITY 0xE5
// AM2320 address
#define AM2320_ADDRESS (0x5C << 1)
// Used for the temperature and humidity buffers
#define DATA_BUFFER_SIZE 8
// External I2C BUS
#define I2C_BUS &furi_hal_i2c_handle_external
typedef enum {
// Typedef enums to make everything easier to read
typedef enum
{
TSSCmdNone,
TSSCmdTemperature,
TSSCmdHumidity
} TSSCmdType;
typedef enum
{
TSSInitializing,
TSSNoSensor,
TSSPendingUpdate,
} TSStatus;
typedef enum {
typedef enum
{
TSEventTypeTick,
TSEventTypeInput,
} TSEventType;
typedef struct {
typedef struct
{
TSEventType type;
InputEvent input;
} TSEvent;
// Possible return values for sensor_cmd
typedef enum
{
TSCmdRet_Error,
TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X,
TSCmdRet_SI701X,
TSCmdRet_AM2320,
} TSCmdRet;
// External NotificationSequence RGB
extern const NotificationSequence sequence_blink_red_100;
extern const NotificationSequence sequence_blink_green_100;
extern const NotificationSequence sequence_blink_blue_100;
// Current status of the temperature sensor app
static TSStatus temperature_sensor_current_status = TSSInitializing;
// We keep track of the last cmd return
static TSCmdRet temperature_sensor_last_cmd_ret = TSCmdRet_Error;
// Temperature and Humidity data buffers, ready to print
char ts_data_buffer_temperature_c[DATA_BUFFER_SIZE];
char ts_data_buffer_temperature_f[DATA_BUFFER_SIZE];
@@ -54,73 +91,132 @@ char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE];
// <sumary>
// Executes an I2C cmd (trx)
// </sumary>
// <TODO>
// CRC
// </TODO>
// <returns>
// true if fetch was successful, false otherwise
// </returns>
static bool temperature_sensor_cmd(uint8_t cmd, uint8_t* buffer, uint8_t size) {
static TSCmdRet temperature_sensor_cmd(TSSCmdType cmd, uint8_t* buffer)
{
uint32_t timeout = furi_ms_to_ticks(100);
bool ret = false;
TSCmdRet ret = TSCmdRet_Error;
// Aquire I2C and check if device is ready, then release
furi_hal_i2c_acquire(I2C_BUS);
if(furi_hal_i2c_is_device_ready(I2C_BUS, HTU21D_ADDRESS, timeout)) {
furi_hal_i2c_release(I2C_BUS);
furi_hal_i2c_acquire(I2C_BUS);
// Transmit given command
ret = furi_hal_i2c_tx(I2C_BUS, HTU21D_ADDRESS, &cmd, 1, timeout);
furi_hal_i2c_release(I2C_BUS);
// Check if HTU2XD, SHT2X, SI702X, SI700X sensor is available
uint8_t isAddress40 = furi_hal_i2c_is_device_ready(I2C_BUS, HTU2XD_SHT2X_SI702X_SI700X_ADDRESS, timeout);
uint8_t isAddress41 = 0;
if(ret) {
uint32_t wait_ticks = furi_ms_to_ticks(50);
furi_delay_tick(wait_ticks);
// Check if SI701X sensor is available if necessary
if (!isAddress40)
isAddress41 = furi_hal_i2c_is_device_ready(I2C_BUS, SI701X_ADDRESS, timeout);
furi_hal_i2c_acquire(I2C_BUS);
// Receive data
ret = furi_hal_i2c_rx(I2C_BUS, HTU21D_ADDRESS, buffer, size, timeout);
furi_hal_i2c_release(I2C_BUS);
if (isAddress40 || isAddress41)
{
uint8_t address = isAddress40 ? HTU2XD_SHT2X_SI702X_SI700X_ADDRESS : SI701X_ADDRESS;
// Better safe than sorry delay
furi_delay_ms(15);
// Extra delay for the SI70XX
if (isAddress41)
furi_delay_ms(50);
// Transmit either the temperature or the humidity command depending on TSSCmdType
uint8_t c = (cmd == TSSCmdTemperature) ? HTU21D_CMD_TEMPERATURE : HTU21D_CMD_HUMIDITY;
if (furi_hal_i2c_tx(I2C_BUS, address, &c, 1, timeout))
{
// Receive data (2 bytes)
if (furi_hal_i2c_rx(I2C_BUS, address, buffer, 2, timeout + 50))
ret = isAddress40 ? TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X : TSCmdRet_SI701X;
}
}
else
{
// The AM2320 goes to sleep after a period of inactivity, wake it up (check AM2320 datasheet for more info)
furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout);
furi_delay_ms(30);
// Check if it's really available
if (furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout))
{
// {Address, Register, Len}
const uint8_t request[3] = { 0x03, 0x00, 0x04 };
if (furi_hal_i2c_tx(I2C_BUS, AM2320_ADDRESS, request, 3, timeout))
{
// 6 bytes - usually 8 but we currently don't check the CRC
if(furi_hal_i2c_rx(I2C_BUS, (uint8_t)AM2320_ADDRESS, buffer, 6, timeout))
ret = TSCmdRet_AM2320;
}
}
} else {
furi_hal_i2c_release(I2C_BUS);
}
furi_hal_i2c_release(I2C_BUS);
temperature_sensor_last_cmd_ret = ret;
return ret;
}
// <sumary>
// Fetches temperature and humidity from sensor
// </sumary>
// <params>
// temperature in C
// humidity in relative humidity
// </params>
// <remarks>
// Temperature and humidity must be preallocated
// Note: CRC is not checked (3rd byte)
// </remarks>
// <TODO>
// CRC
// </TODO>
// <returns>
// true if fetch was successful, false otherwise
// </returns>
static bool temperature_sensor_fetch_data(double* temperature, double* humidity) {
static bool temperature_sensor_fetch_data(double* temperature, double* humidity)
{
bool ret = false;
uint16_t adc_raw;
uint8_t buffer[2] = {0x00};
uint8_t buffer[DATA_BUFFER_SIZE] = { 0x00 };
// Fetch temperature
ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2);
if(ret) {
// Check if the sensor is the HTU21D by attempting to fetch the temperature
TSCmdRet cmdRet = temperature_sensor_cmd(TSSCmdTemperature, buffer);
if (cmdRet == TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X || cmdRet == TSCmdRet_SI701X)
{
// Calculate temperature
adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1]));
*temperature = (float)(adc_raw * 175.72 / 65536.00) - 46.85;
// Fetch humidity
ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_HUMIDITY, buffer, 2);
if(ret) {
if (temperature_sensor_cmd(TSSCmdHumidity, buffer))
{
// Calculate humidity
adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1]));
*humidity = (float)(adc_raw * 125.0 / 65536.00) - 6.0;
ret = true;
}
}
else if (cmdRet == TSCmdRet_AM2320)
{
// The AM2320 returns all the data immediately so we just process it all
// Note: CRC isn't currently present in the buffer
// Temperature
float temp = (((buffer[4] & 0x7F) << 8) + buffer[5]) / 10;
*temperature = ((buffer[4] & 0x80) >> 7) == 1 ? temp * (-1) : temp;
// Humidity
temp = ((buffer[2] << 8) + buffer[3]) / 10;
*humidity = temp;
ret = true;
}
return ret;
}
@@ -128,24 +224,50 @@ static bool temperature_sensor_fetch_data(double* temperature, double* humidity)
// <sumary>
// Draw callback
// </sumary>
static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx)
{
UNUSED(ctx);
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 2, 10, "HTU21D/Si7021 Sensor");
// Update title accordingly (this could be improved by checking the hardware id)
switch (temperature_sensor_last_cmd_ret)
{
case TSCmdRet_Error:
canvas_draw_str(canvas, 2, 10, "Temperature Sensor");
break;
case TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X:
canvas_draw_str(canvas, 2, 10, "HTU/SHT/SI70 Sensor");
break;
case TSCmdRet_SI701X:
canvas_draw_str(canvas, 2, 10, "SI701X Sensor");
break;
case TSCmdRet_AM2320:
canvas_draw_str(canvas, 2, 10, "AM2320 Sensor");
break;
default:
break;
}
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 62, "Press back to exit.");
switch(temperature_sensor_current_status) {
switch (temperature_sensor_current_status)
{
case TSSInitializing:
canvas_draw_str(canvas, 2, 30, "Initializing..");
break;
case TSSNoSensor:
canvas_draw_str(canvas, 2, 30, "No sensor found!");
break;
case TSSPendingUpdate: {
case TSSPendingUpdate:
{
canvas_draw_str(canvas, 3, 24, "Temperature");
canvas_draw_str(canvas, 68, 24, "Humidity");
@@ -165,8 +287,8 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
canvas_draw_str(canvas, 100, 38, "%");
canvas_draw_str(canvas, 68, 48, ts_data_buffer_absolute_humidity);
canvas_draw_str(canvas, 100, 48, "g/m3");
} break;
}
break;
default:
break;
}
@@ -175,31 +297,33 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
// <sumary>
// Input callback
// </sumary>
static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx) {
static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx)
{
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
TSEvent event = {.type = TSEventTypeInput, .input = *input_event};
TSEvent event = { .type = TSEventTypeInput, .input = *input_event };
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
// <sumary>
// Timer callback
// </sumary>
static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) {
static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue)
{
furi_assert(event_queue);
TSEvent event = {.type = TSEventTypeTick};
TSEvent event = { .type = TSEventTypeTick };
furi_message_queue_put(event_queue, &event, 0);
}
// <sumary>
// App entry point
// </sumary>
int32_t temperature_sensor_app(void* p) {
int32_t temperature_sensor_app(void* p)
{
UNUSED(p);
furi_hal_power_suppress_charge_enter();
// Declare our variables and assign variables a default value
TSEvent tsEvent;
bool sensorFound = false;
@@ -216,8 +340,7 @@ int32_t temperature_sensor_app(void* p) {
view_port_input_callback_set(view_port, temperature_sensor_input_callback, event_queue);
// Create timer and register its callback
FuriTimer* timer =
furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue);
FuriTimer* timer = furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency());
// Register viewport
@@ -227,51 +350,57 @@ int32_t temperature_sensor_app(void* p) {
// Used to notify the user by blinking red (error) or blue (fetch successful)
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
while(1) {
while (1)
{
furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk);
// Handle events
if(tsEvent.type == TSEventTypeInput) {
// Exit on back key
if(tsEvent.input.key ==
InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort)
break;
if (tsEvent.type == TSEventTypeInput)
{
// Exit on back key
if (tsEvent.input.key == InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort)
break;
}
else if (tsEvent.type == TSEventTypeTick)
{
} else if(tsEvent.type == TSEventTypeTick) {
// Update sensor data
// Fetch data and set the sensor current status accordingly
sensorFound = temperature_sensor_fetch_data(&celsius, &rel_humidity);
temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor);
if(sensorFound) {
if (sensorFound)
{
// Blink blue
notification_message(notifications, &sequence_blink_blue_100);
if(celsius != TS_DEFAULT_VALUE && rel_humidity != TS_DEFAULT_VALUE) {
if (celsius != TS_DEFAULT_VALUE && rel_humidity != TS_DEFAULT_VALUE)
{
// Convert celsius to fahrenheit
fahrenheit = (celsius * 9 / 5) + 32;
// Calculate absolute humidity - For more info refer to https://github.com/Mywk/FlipperTemperatureSensor/issues/1
// Calculate saturation vapour pressure first
vapour_pressure =
(double)6.11 *
pow(10, (double)(((double)7.5 * celsius) / ((double)237.3 + celsius)));
vapour_pressure = (double)6.11 * pow(10, (double)(((double)7.5 * celsius) / ((double)237.3 + celsius)));
// Then the vapour pressure in Pa
vapour_pressure = vapour_pressure * rel_humidity;
// Calculate absolute humidity
abs_humidity =
(double)2.16679 * (double)(vapour_pressure / ((double)273.15 + celsius));
abs_humidity = (double)2.16679 * (double)(vapour_pressure / ((double)273.15 + celsius));
// Fill our buffers here, not on the canvas draw callback
snprintf(ts_data_buffer_temperature_c, DATA_BUFFER_SIZE, "%.2f", celsius);
snprintf(ts_data_buffer_temperature_f, DATA_BUFFER_SIZE, "%.2f", fahrenheit);
snprintf(
ts_data_buffer_relative_humidity, DATA_BUFFER_SIZE, "%.2f", rel_humidity);
snprintf(
ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity);
snprintf(ts_data_buffer_relative_humidity, DATA_BUFFER_SIZE, "%.2f", rel_humidity);
snprintf(ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity);
}
}
else
{
} else {
// Reset our variables to their default values
celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE;
@@ -280,8 +409,7 @@ int32_t temperature_sensor_app(void* p) {
}
}
uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500);
furi_delay_tick(wait_ticks);
furi_delay_ms(!sensorFound ? 100 : 500);
}
// Dobby is freee (free our variables, Flipper will crash if we don't do this!)
@@ -294,4 +422,4 @@ int32_t temperature_sensor_app(void* p) {
furi_record_close(RECORD_GUI);
return 0;
}
}