Hello!
I'm working on a project, using GY-39. Here are usage information:
GY-39 Environmental Sensor Module (pressure, temperature, humidity, illuminance)
Detailed product description
Module GY-39 combines temperature, air pressure, relative humidity, and illumination measurements, and has a built-in controller (MCU) that processes the data and sends it via UART or I2C. Due to its 3-5 V power supply and TTL interface, it is suitable for Arduino, ESP32, and other development boards for electronics projects, DIY prototyping, and education. Typical uses include weather stations, microclimate control in greenhouses, smart lighting, and recording environmental parameters in IoT devices.
Note on sensors: GY-39 versions are usually based on bme280 (temp./humidity/pressure) and bh1750 or max44009 (light); check the version in the photo of your product.
Technical specifications
- sensors: bme280 (temperature, humidity, pressure) + bh1750 or max44009 (light intensity)
- Temperature measuring range: approx. −40 to +85 °C
- Humidity measuring range: 0 to 100% RH
- pressure measuring range: 300 to 1100 hPa
- Illumination measurement range: from low lux to daylight (depending on version)
- communication mode: uart (ttl) or i2c; “continuous” and “query” modes
- typical uart speeds: 9600 or 115200 bps
- i2c address: often 0x5b (7-bit) for mcu-i2c mode; direct chips have their own addresses (e.g. bme280 0x76/0x77, bh1750 0x23)
- power supply: 3–5 V DC
- refresh rate: up to approximately 10 Hz
- typical pins: vcc, gnd, ct (uart_tx/i2c_scl), dr (uart_rx/i2c_sda), s0 (uart/i2c select), s1 (chip-only), int (interrupt for light sensor)
Communication with Arduino UNO (practical)
There are three modes; for UNO, the simplest is UART.
- UART mode (recommended for quick start)
- setting: s0 = “high” (uart), s1 = “high” (mcu active)
- links:
- vcc → 5v (or 3.3v), gnd → gnd
- tx module (ct) → uno d2, rx module (dr) → uno d3 (use SoftwareSerial; d0/d1 are occupied by usb)
- if you are not sure about the 5 in input tolerance on the module, use a divider on the uno tx → module rx line (e.g. 1 kΩ + 2 kΩ)
- speed: start with 9600 bps; if you get “strange” characters, switch to 115200 bps
- MCU-I2C mode (read module registers)
- setting: s0 = “low” (i2c), s1 = “high” (mcu active)
- connections: vcc → 5v, gnd → gnd, ct → scl (uno a5), dr → sda (uno a4)
- notes: the default i2c address is 0x5b on most versions; you read the prepared values from the module registers (the layout is usually described in the printed material or product sheet)
- “Chip-only” direct i2c to sensors (advanced use)
- setting: s1 = “low” (mcu bypasses sensors), s0 = “low” (i2c)
- connections: a4/a5 to sda/scl of sensors, vcc → 3.3v (recommended), add a level converter, as sensors are usually 3.3v logic
- notes: addresses are typically bme280 0x76/0x77 and bh1750 0x23; use the appropriate arduino libraries
How to get reliable measurements
- installation: mount the module away from heat and draft sources; point the light sensor towards the area you want to monitor
- power supply: when powered from USB, consider noise; for more accurate measurements, you can use filtering or a separate power supply
- communication: for longer i2c lines, reduce the speed (e.g. 50–100 kHz) and add appropriate pull-up resistors to sda/scl
Where is the module used in practice?
- smart home: automatic dimmers, ventilation based on humidity and temperature
- IoT prototypes: recording environmental parameters, warnings when exceeded
- education: exercises in i2c/uart communication, calibration and data processing
- environmental control: greenhouses, display cases, storage of sensitive materials
I decided to use the UART mode, because it says here, it is the easier to use with Aruino UNO, which I'm using for this project. The problem is, I'm getting weird data, like Temperature: 176.74 °C
Humidity: 24.83%
Pressure: 99095.19 hPa
Illumination: 327745723 lux
My code:
#include <SoftwareSerial.h>
SoftwareSerial gySerial(2, 3); // RX, TX on arduino
const int PACKET_SIZE = 33;
byte buffer[PACKET_SIZE];
int index = 0;
bool headerFound = false;
void setup() {
Serial.begin(9600);
gySerial.begin(9600);
Serial.println("starting gy39...");
}
void loop() {
while (gySerial.available()) {
byte incoming = gySerial.read();
if (!headerFound) {
if (index == 0 && incoming == 0x5A) {
buffer[index++] = incoming;
} else if (index == 1) {
if (incoming == 0x5A) {
buffer[index++] = incoming;
headerFound = true;
} else {
// no header
index = 0;
}
} else {
index = 0;
}
} else {
buffer[index++] = incoming;
if (index == PACKET_SIZE) {
parsePacket(buffer);
// reset
index = 0;
headerFound = false;
}
}
}
}
void parsePacket(byte* data) {
// check header
if (data[0] != 0x5A || data[1] != 0x5A) {
Serial.println("Mistake, wrong header!");
return;
}
// Temperature (2 bytes, int16_t)
int16_t tempRaw = (data[2] << 8) | data[3];
float temperatura = tempRaw / 100.0;
//humidityt (2 bytes, int16_t)
int16_t humRaw = (data[4] << 8) | data[5];
float vlaga = humRaw / 100.0;
// pressure (4 bytes, uint32_t)
uint32_t presRaw = ((uint32_t)data[6] << 24) |
((uint32_t)data[7] << 16) |
((uint32_t)data[8] << 8) |
data[9];
float tlak = presRaw / 100.0;
// light (4 bytes, uint32_t)
uint32_t lightRaw = ((uint32_t)data[10] << 24) |
((uint32_t)data[11] << 16) |
((uint32_t)data[12] << 8) |
data[13];
Serial.print("Temperature: "); Serial.print(temperature); Serial.println(" °C");
Serial.print("Humidity: "); Serial.print(humidity); Serial.println(" %");
Serial.print("Pressure: "); Serial.print(tpressure); Serial.println(" hPa");
Serial.print("Light: "); Serial.print(lightRaw); Serial.println(" lux");
Serial.println("----------------------");
}
any idea, what could have possibly gone wrong?
