From 731d3be0448540d1990450d9090602208907a984 Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Thu, 24 Nov 2022 03:41:21 -0500 Subject: [PATCH] up temp sensor --- ReadMe.md | 3 +- .../plugins/htu21d_temp_sensor/Readme.md | 62 +++- .../htu21d_temp_sensor/application.fam | 4 +- .../htu21d_temp_sensor/temperature_sensor.c | 264 +++++++++++++----- 4 files changed, 255 insertions(+), 78 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 1d2a99e44..d0ef311a0 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -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) diff --git a/applications/plugins/htu21d_temp_sensor/Readme.md b/applications/plugins/htu21d_temp_sensor/Readme.md index 0311294ea..45c332306 100644 --- a/applications/plugins/htu21d_temp_sensor/Readme.md +++ b/applications/plugins/htu21d_temp_sensor/Readme.md @@ -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) +
+# 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). \ No newline at end of file diff --git a/applications/plugins/htu21d_temp_sensor/application.fam b/applications/plugins/htu21d_temp_sensor/application.fam index e25af12ad..9ae3bdffd 100644 --- a/applications/plugins/htu21d_temp_sensor/application.fam +++ b/applications/plugins/htu21d_temp_sensor/application.fam @@ -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"], diff --git a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c index f3ed15dbc..02e662d60 100644 --- a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c +++ b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c @@ -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 #include @@ -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]; // // Executes an I2C cmd (trx) // +// +// CRC +// // // true if fetch was successful, false otherwise // -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; } // // Fetches temperature and humidity from sensor // +// +// temperature in C +// humidity in relative humidity +// // // Temperature and humidity must be preallocated -// Note: CRC is not checked (3rd byte) // +// +// CRC +// // // true if fetch was successful, false otherwise // -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) // // Draw callback // -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) { // // Input callback // -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); } // // Timer callback // -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); } // // App entry point // -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; -} +} \ No newline at end of file