From 9c4612e571db42f5e6123a3f159e01337453a6af Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:18:08 +0300 Subject: [PATCH] Plugins: New AM2320 Sensor plugin --- .../am2320_temp_sensor/application.fam | 14 + .../am2320_temp_sensor/temperature_sensor.c | 336 ++++++++++++++++++ .../temperature_sensor.png | Bin .../Readme.md | 0 .../application.fam | 2 +- .../docs/App.png | Bin .../docs/Connection.png | Bin .../docs/Flipper.png | Bin .../temperature_sensor.c | 0 .../htu21d_temp_sensor/temperature_sensor.png | Bin 0 -> 181 bytes 10 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 applications/plugins/am2320_temp_sensor/application.fam create mode 100644 applications/plugins/am2320_temp_sensor/temperature_sensor.c rename applications/plugins/{temperature_sensor => am2320_temp_sensor}/temperature_sensor.png (100%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/Readme.md (100%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/application.fam (89%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/docs/App.png (100%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/docs/Connection.png (100%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/docs/Flipper.png (100%) rename applications/plugins/{temperature_sensor => htu21d_temp_sensor}/temperature_sensor.c (100%) create mode 100644 applications/plugins/htu21d_temp_sensor/temperature_sensor.png diff --git a/applications/plugins/am2320_temp_sensor/application.fam b/applications/plugins/am2320_temp_sensor/application.fam new file mode 100644 index 0000000000..cd4afdc4a7 --- /dev/null +++ b/applications/plugins/am2320_temp_sensor/application.fam @@ -0,0 +1,14 @@ +App( + appid="am2320_temp_sensor", + name="[AM2320] Temp. Sensor", + apptype=FlipperAppType.EXTERNAL, + entry_point="temperature_sensor_app", + cdefines=["APP_TEMPERATURE_SENSOR"], + requires=[ + "gui", + ], + stack_size=2 * 1024, + order=90, + fap_icon="temperature_sensor.png", + fap_category="GPIO", +) diff --git a/applications/plugins/am2320_temp_sensor/temperature_sensor.c b/applications/plugins/am2320_temp_sensor/temperature_sensor.c new file mode 100644 index 0000000000..236c5e2d21 --- /dev/null +++ b/applications/plugins/am2320_temp_sensor/temperature_sensor.c @@ -0,0 +1,336 @@ +/* Flipper Plugin to read the values from a AM2320/AM2321 Sensor */ +/* Created by @xMasterX, original app (was used as template) by Mywk - https://github.com/Mywk */ +/* Lib used as reference: https://github.com/Gozem/am2320/blob/master/am2321.c*/ +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#define TS_DEFAULT_VALUE 0xFFFF + +#define AM2320_ADDRESS (0x5C << 1) + +#define DATA_BUFFER_SIZE 8 + +// External I2C BUS +#define I2C_BUS &furi_hal_i2c_handle_external + +typedef enum { + TSSInitializing, + TSSNoSensor, + TSSPendingUpdate, +} TSStatus; + +typedef enum { + TSEventTypeTick, + TSEventTypeInput, +} TSEventType; + +typedef struct { + TSEventType type; + InputEvent input; +} TSEvent; + +extern const NotificationSequence sequence_blink_red_100; +extern const NotificationSequence sequence_blink_blue_100; + +static TSStatus temperature_sensor_current_status = TSSInitializing; + +// 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]; +char ts_data_buffer_relative_humidity[DATA_BUFFER_SIZE]; +char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE]; + +// CRC16 calculation +static uint16_t get_crc16(const uint8_t* buf, size_t len) { + uint16_t crc = 0xFFFF; + + while(len--) { + crc ^= (uint16_t)*buf++; + for(unsigned i = 0; i < 8; i++) { + if(crc & 0x0001) { + crc >>= 1; + crc ^= 0xA001; + } else { + crc >>= 1; + } + } + } + + return crc; +} +// Combine bytes +static uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { + return ((uint16_t)msb << 8) | (uint16_t)lsb; +} + +// Executes an I2C wake up, sends command and reads result +// true if fetch was successful, false otherwise +static bool temperature_sensor_get_data(uint8_t* buffer, uint8_t size) { + uint32_t timeout = furi_ms_to_ticks(100); + uint8_t cmdbuffer[3] = {0, 0, 0}; + bool ret = false; + + // Aquire I2C bus + furi_hal_i2c_acquire(I2C_BUS); + + // Wake UP AM2320 (sensor goes to sleep to not warm up and affect the humidity sensor) + furi_hal_i2c_is_device_ready(I2C_BUS, (uint8_t)AM2320_ADDRESS, timeout); + // Check if device woken up then we do next stuff + if(furi_hal_i2c_is_device_ready(I2C_BUS, (uint8_t)AM2320_ADDRESS, timeout)) { + // Wait a bit + furi_delay_us(1000); + + // Prepare command: Addr 0x03, start register = 0x00, number of registers to read = 0x04 + cmdbuffer[0] = 0x03; + cmdbuffer[1] = 0x00; + cmdbuffer[2] = 0x04; + + // Transmit command to read registers + ret = furi_hal_i2c_tx(I2C_BUS, (uint8_t)AM2320_ADDRESS, cmdbuffer, 3, timeout); + + // Wait a bit + furi_delay_us(1600); + if(ret) { + /* + * Read out 8 bytes of data + * Byte 0: Should be Modbus function code 0x03 + * Byte 1: Should be number of registers to read (0x04) + * Byte 2: Humidity msb + * Byte 3: Humidity lsb + * Byte 4: Temperature msb + * Byte 5: Temperature lsb + * Byte 6: CRC lsb byte + * Byte 7: CRC msb byte + */ + ret = furi_hal_i2c_rx(I2C_BUS, (uint8_t)AM2320_ADDRESS, buffer, size, timeout); + } + } + // Release i2c bus + furi_hal_i2c_release(I2C_BUS); + + return ret; +} + +// Fetches temperature and humidity from sensor +// Temperature and humidity must be preallocated +// true if fetch was successful, false otherwise +static bool temperature_sensor_fetch_info(double* temperature, double* humidity) { + *humidity = (float)0; + bool ret = false; + + uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + // Fetch data from sensor + ret = temperature_sensor_get_data(buffer, 8); + + // If we got no result + if(!ret) return false; + + if(buffer[0] != 0x03) return false; // must be 0x03 modbus reply + if(buffer[1] != 0x04) return false; // must be 0x04 number of registers reply + + // Check CRC16 sum, if not correct - return false + uint16_t crcdata = get_crc16(buffer, 6); + uint16_t crcread = combine_bytes(buffer[7], buffer[6]); + if(crcdata != crcread) return false; + + // Combine bytes for temp and humidity + uint16_t temp16 = combine_bytes(buffer[4], buffer[5]); + uint16_t humi16 = combine_bytes(buffer[2], buffer[3]); + + /* Temperature resolution is 16Bit, + * temperature highest bit (Bit15) is equal to 1 indicates a + * negative temperature, the temperature highest bit (Bit15) + * is equal to 0 indicates a positive temperature; + * temperature in addition to the most significant bit (Bit14 ~ Bit0) + * indicates the temperature sensor string value. + * Temperature sensor value is a string of 10 times the + * actual temperature value. + */ + if(temp16 & 0x8000) { + temp16 = -(temp16 & 0x7FFF); + } + + // Prepare output data + *temperature = (float)temp16 / 10.0; + *humidity = (float)humi16 / 10.0; + + return true; +} + +// Draw callback + +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, "AM2320/AM2321 Sensor"); + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 2, 62, "Press back to exit."); + + 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: { + canvas_draw_str(canvas, 3, 24, "Temperature"); + canvas_draw_str(canvas, 68, 24, "Humidity"); + + // Draw vertical lines + canvas_draw_line(canvas, 61, 16, 61, 50); + canvas_draw_line(canvas, 62, 16, 62, 50); + + // Draw horizontal line + canvas_draw_line(canvas, 2, 27, 122, 27); + + // Draw temperature and humidity values + canvas_draw_str(canvas, 8, 38, ts_data_buffer_temperature_c); + canvas_draw_str(canvas, 42, 38, "C"); + canvas_draw_str(canvas, 8, 48, ts_data_buffer_temperature_f); + canvas_draw_str(canvas, 42, 48, "F"); + canvas_draw_str(canvas, 68, 38, ts_data_buffer_relative_humidity); + 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; + default: + break; + } +} + +// Input callback + +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}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +// Timer callback + +static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + TSEvent event = {.type = TSEventTypeTick}; + furi_message_queue_put(event_queue, &event, 0); +} + +// App entry point + +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; + double celsius, fahrenheit, rel_humidity, abs_humidity = TS_DEFAULT_VALUE; + + // Used for absolute humidity calculation + double vapour_pressure = 0; + + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent)); + + // Register callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, temperature_sensor_draw_callback, NULL); + 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); + furi_timer_start(timer, furi_kernel_get_tick_frequency()); + + // Register viewport + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + // Used to notify the user by blinking red (error) or blue (fetch successful) + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + + 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; + + } else if(tsEvent.type == TSEventTypeTick) { + // Update sensor data + // Fetch data and set the sensor current status accordingly + sensorFound = temperature_sensor_fetch_info(&celsius, &rel_humidity); + temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor); + + if(sensorFound) { + // Blink blue + notification_message(notifications, &sequence_blink_blue_100); + + 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))); + // 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)); + + // 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); + } + + } else { + // Reset our variables to their default values + celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE; + + // Blink red + notification_message(notifications, &sequence_blink_red_100); + } + } + + uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500); + furi_delay_tick(wait_ticks); + } + + furi_hal_power_suppress_charge_exit(); + // Dobby is freee (free our variables, Flipper will crash if we don't do this!) + furi_timer_free(timer); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_message_queue_free(event_queue); + + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_GUI); + + return 0; +} diff --git a/applications/plugins/temperature_sensor/temperature_sensor.png b/applications/plugins/am2320_temp_sensor/temperature_sensor.png similarity index 100% rename from applications/plugins/temperature_sensor/temperature_sensor.png rename to applications/plugins/am2320_temp_sensor/temperature_sensor.png diff --git a/applications/plugins/temperature_sensor/Readme.md b/applications/plugins/htu21d_temp_sensor/Readme.md similarity index 100% rename from applications/plugins/temperature_sensor/Readme.md rename to applications/plugins/htu21d_temp_sensor/Readme.md diff --git a/applications/plugins/temperature_sensor/application.fam b/applications/plugins/htu21d_temp_sensor/application.fam similarity index 89% rename from applications/plugins/temperature_sensor/application.fam rename to applications/plugins/htu21d_temp_sensor/application.fam index f465c5c934..b3101f42e4 100644 --- a/applications/plugins/temperature_sensor/application.fam +++ b/applications/plugins/htu21d_temp_sensor/application.fam @@ -1,6 +1,6 @@ App( appid="temperature_sensor", - name="[HTU21D] Temp Sensor", + name="[HTU21D] Temp. Sensor", apptype=FlipperAppType.EXTERNAL, entry_point="temperature_sensor_app", cdefines=["APP_TEMPERATURE_SENSOR"], diff --git a/applications/plugins/temperature_sensor/docs/App.png b/applications/plugins/htu21d_temp_sensor/docs/App.png similarity index 100% rename from applications/plugins/temperature_sensor/docs/App.png rename to applications/plugins/htu21d_temp_sensor/docs/App.png diff --git a/applications/plugins/temperature_sensor/docs/Connection.png b/applications/plugins/htu21d_temp_sensor/docs/Connection.png similarity index 100% rename from applications/plugins/temperature_sensor/docs/Connection.png rename to applications/plugins/htu21d_temp_sensor/docs/Connection.png diff --git a/applications/plugins/temperature_sensor/docs/Flipper.png b/applications/plugins/htu21d_temp_sensor/docs/Flipper.png similarity index 100% rename from applications/plugins/temperature_sensor/docs/Flipper.png rename to applications/plugins/htu21d_temp_sensor/docs/Flipper.png diff --git a/applications/plugins/temperature_sensor/temperature_sensor.c b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c similarity index 100% rename from applications/plugins/temperature_sensor/temperature_sensor.c rename to applications/plugins/htu21d_temp_sensor/temperature_sensor.c diff --git a/applications/plugins/htu21d_temp_sensor/temperature_sensor.png b/applications/plugins/htu21d_temp_sensor/temperature_sensor.png new file mode 100644 index 0000000000000000000000000000000000000000..b6fe6d7feb1fa91f43ea3ce545bf3056f0f8a4b8 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?X?_wfUrhf?l33jv*SsQ~MdY7!){|xBmaXbJmiR8&)uH zEaAIqH<2lH>YXg@Xy%9c9e?=GOkB=*{m{gR2NzH1OsFVdQ&MBb@0O^W43IG5A literal 0 HcmV?d00001