Skip to content

fix: fix data acquisition from SHT21 temperature and humidity sensor #2774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/src/main/java/io/pslab/activity/SensorActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
Expand Down Expand Up @@ -192,7 +193,7 @@ protected Void doInBackground(Void... voids) {
// Perform I2C scan to detect connected sensors
detectedSensors = i2c.scan(null);
} catch (IOException | NullPointerException e) {
e.printStackTrace();
Log.w(TAG, "Error scanning for sensors", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ public class CommunicationHandler {
private UsbSerialDriver driver;
private UsbSerialPort port;
public UsbDevice mUsbDevice;
List<UsbSerialDriver> drivers;

public static final int DEFAULT_READ_BUFFER_SIZE = 32 * 1024;
public static final int DEFAULT_WRITE_BUFFER_SIZE = 32 * 1024;

private byte[] mReadBuffer;
private byte[] mWriteBuffer;

public CommunicationHandler(UsbManager usbManager) {
this.mUsbManager = usbManager;
Expand All @@ -45,7 +42,7 @@ public CommunicationHandler(UsbManager usbManager) {
customTable.addProduct(PSLAB_VENDOR_ID_V6, PSLAB_PRODUCT_ID_V6, Cp21xxSerialDriver.class);

UsbSerialProber prober = new UsbSerialProber(customTable);
drivers = prober.findAllDrivers(usbManager);
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);

if (drivers.isEmpty()) {
Log.d(TAG, "No drivers found");
Expand All @@ -56,7 +53,6 @@ public CommunicationHandler(UsbManager usbManager) {
mUsbDevice = driver.getDevice();
}
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
}

public void open(int baudRate) throws IOException {
Expand Down Expand Up @@ -115,7 +111,7 @@ public int read(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOExce
bytesToBeReadTemp -= readNow;
}
}
Log.v("Bytes Read", "" + numBytesRead);
Log.v(TAG, "Bytes Read: " + numBytesRead);
return numBytesRead;
}

Expand All @@ -135,7 +131,7 @@ public int readCdcAcm(byte[] dest, int bytesToBeRead, int timeoutMillis) throws
bytesToBeReadTemp -= readNow;
}
}
Log.v("Bytes Read", "" + numBytesRead);
Log.v(TAG, "Bytes Read: " + numBytesRead);
return numBytesRead;
}

Expand Down
17 changes: 13 additions & 4 deletions app/src/main/java/io/pslab/communication/peripherals/I2C.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package io.pslab.communication.peripherals;

import android.os.SystemClock;
import android.util.Log;

import io.pslab.communication.CommandsProto;
import io.pslab.communication.PacketHandler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

import io.pslab.communication.CommandsProto;
import io.pslab.communication.PacketHandler;

/**
* Created by viveksb007 on 28/3/17.
*/
Expand Down Expand Up @@ -140,6 +139,16 @@ public int readStatus() throws IOException {
return val;
}

/**
* Reads data from an I2C device.
*
* @param deviceAddress address of the device to read from
* @param registerAddress address of the register to read from
* @param bytesToRead number of bytes to read from the device
* @return bytes read from the device plus a status byte as the last element (so this will be
* {@code bytesToRead} plus one)
* @throws IOException if data cannot be read
*/
public ArrayList<Integer> readBulk(int deviceAddress, int registerAddress, int bytesToRead) throws IOException {
packetHandler.sendByte(commandsProto.I2C_HEADER);
packetHandler.sendByte(commandsProto.I2C_READ_BULK);
Expand Down
114 changes: 57 additions & 57 deletions app/src/main/java/io/pslab/communication/sensors/SHT21.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@

import android.util.Log;

import io.pslab.communication.ScienceLab;
import io.pslab.communication.peripherals.I2C;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.pslab.communication.ScienceLab;
import io.pslab.communication.peripherals.I2C;

/**
* Created by akarshan on 4/16/17.
* Implementation of communication with SHT21 temperature / humidity sensor.
* <p>
* See <a href="https://sensirion.com/media/documents/120BBE4C/63500094/Sensirion_Datasheet_Humidity_Sensor_SHT21.pdf">
* Datasheet SHT21</a> for the calculations for temperature and humidity.
* <p>
* Example code for CRC calculation can be found in the ZIP file
* <a href="https://sensirion.com/resource/software/code/sht21">Sample code SHT21</a>
*/

public class SHT21 {
private String TAG = "SHT21";
private int RESET = 0XFE;
private int TEMP_ADDRESS = 0xF3;
private int HUMIDITY_ADDRESS = 0xF5;
private int selected = 0xF3;
private int ADDRESS = 0x40;

public int NUMPLOTS = 1;
public String[] PLOTNAMES = {"Data"};
public String name = "Humidity/Temperature";
public enum Mode {
TEMPERATURE(TEMP_ADDRESS), HUMIDITY(HUMIDITY_ADDRESS);

public ArrayList<String> selectParameter = new ArrayList<>(Arrays.asList("temperature", "humidity"));
private I2C i2c;
final int registerAddress;

Mode(int registerAddress) {
this.registerAddress = registerAddress;
}
}

private static final String TAG = SHT21.class.getSimpleName();
private static final int RESET = 0XFE;
private static final int TEMP_ADDRESS = 0xE3;
private static final int HUMIDITY_ADDRESS = 0xE5;
private static final int ADDRESS = 0x40;

private Mode selected = Mode.TEMPERATURE;

private final I2C i2c;

public SHT21(I2C i2c, ScienceLab scienceLab) throws IOException, InterruptedException {
this.i2c = i2c;
Expand All @@ -41,38 +52,27 @@ private void init() throws IOException, InterruptedException {
TimeUnit.MILLISECONDS.sleep(100);
}

private ArrayList<Double> rawToTemp(ArrayList<Byte> vals) {
double v;
ArrayList<Double> v1 = new ArrayList<>();
if (vals.size() != 0) {
v = (vals.get(0) << 8) | (vals.get(1) & 0xFC);
v *= 175.72;
v /= (1 << 16);
v -= 46.85;
v1.add(v);
return v1;
private static Double rawToTemp(List<Integer> vals) {
if (vals.size() >= 2) {
double v = ((vals.get(0) & 0xFF) << 8) | (vals.get(1) & 0xFC);
return -46.85 + 175.72 * (v / (1 << 16));
} else return null;
}

private ArrayList<Double> rawToRH(ArrayList<Byte> vals) {
double v;
ArrayList<Double> v1 = new ArrayList<>();
if (vals.size() != 0) {
v = (vals.get(0) << 8) | (vals.get(1) & 0xFC);
v *= 125.;
v /= (1 << 16);
v -= 6;
v1.add(v);
return v1;
private static Double rawToRH(List<Integer> vals) {
if (vals.size() >= 2) {
double v = ((vals.get(0) & 0xFF) << 8) | (vals.get(1) & 0xFC);
return -6 + 125 * (v / (1 << 16));
} else return null;
}

private static int calculateChecksum(ArrayList<Byte> data, int numberOfBytes) {
private static int calculateChecksum(List<Integer> data, int numberOfBytes) {

//CRC
int POLYNOMIAL = 0x131, byteCtr, crc = 0;
final int POLYNOMIAL = 0x31;
int crc = 0;
//calculates 8-Bit checksum with given polynomial
for (byteCtr = 0; byteCtr < numberOfBytes; byteCtr++) {
for (int byteCtr = 0; byteCtr < numberOfBytes; byteCtr++) {
crc ^= data.get(byteCtr);
for (int bit = 8; bit > 0; bit--) {
if ((crc & 0X80) != 0)
Expand All @@ -84,29 +84,29 @@ private static int calculateChecksum(ArrayList<Byte> data, int numberOfBytes) {
return crc;
}

public void selectParameter(String param) {
if (param.equals("temperature"))
selected = TEMP_ADDRESS;
else if (param.equals("humidity"))
selected = HUMIDITY_ADDRESS;
public void setMode(Mode mode) {
selected = mode;
}

public ArrayList<Double> getRaw() throws IOException, InterruptedException {
ArrayList<Byte> vals;
i2c.writeBulk(ADDRESS, new int[]{selected});
if (selected == TEMP_ADDRESS)
public Double getRaw() throws IOException, InterruptedException {
List<Integer> vals;
i2c.writeBulk(ADDRESS, new int[]{selected.registerAddress});
if (selected == Mode.TEMPERATURE)
TimeUnit.MILLISECONDS.sleep(100);
else if (selected == HUMIDITY_ADDRESS)
else if (selected == Mode.HUMIDITY)
TimeUnit.MILLISECONDS.sleep(50);
vals = i2c.simpleRead(ADDRESS, 3);
if (vals.size() != 0) {
if (calculateChecksum(vals, 2) != vals.get(2))
Log.v(TAG, vals.toString());
vals = i2c.readBulk(ADDRESS, selected.registerAddress, 3);
if (vals.isEmpty()) {
Log.v(TAG, "No data received.");
return null;
} else if ((calculateChecksum(vals, 2) & 0xFF) != (vals.get(2) & 0xFF)) {
Log.v(TAG, "Error in checksum.");
return null;
}
if (selected == TEMP_ADDRESS)

if (selected == Mode.TEMPERATURE)
return rawToTemp(vals);
else if (selected == HUMIDITY_ADDRESS)
else if (selected == Mode.HUMIDITY)
return rawToRH(vals);
else
return null;
Expand Down
30 changes: 15 additions & 15 deletions app/src/main/java/io/pslab/fragment/ThermometerDataFragment.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.pslab.fragment;

import static android.content.Context.SENSOR_SERVICE;
import static io.pslab.others.CSVLogger.CSV_DIRECTORY;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.hardware.Sensor;
Expand All @@ -10,17 +13,16 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import androidx.annotation.NonNull;

import com.google.android.material.snackbar.Snackbar;
import androidx.fragment.app.Fragment;

import androidx.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager;

import com.github.anastr.speedviewlib.PointerSpeedometer;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
Expand All @@ -29,6 +31,7 @@
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.google.android.material.snackbar.Snackbar;

import java.io.File;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -58,12 +61,10 @@
import io.pslab.others.CustomSnackBar;
import io.pslab.others.ScienceLabCommon;

import static android.content.Context.SENSOR_SERVICE;
import static io.pslab.others.CSVLogger.CSV_DIRECTORY;

public class ThermometerDataFragment extends Fragment implements OperationCallback {

private static final String TEMPERATURE = "temperature";
private static final String TAG = ThermometerDataFragment.class.getSimpleName();

private static final CSVDataLine CSV_HEADER = new CSVDataLine()
.add("Timestamp")
.add("DateTime")
Expand Down Expand Up @@ -123,7 +124,7 @@ public static ThermometerDataFragment newInstance() {

public static void setParameters(int updatePeriod, String type, String unit) {
ThermometerDataFragment.updatePeriod = updatePeriod;
ThermometerDataFragment.sensorType = Integer.valueOf(type);
ThermometerDataFragment.sensorType = Integer.parseInt(type);
ThermometerDataFragment.unit = unit;

}
Expand Down Expand Up @@ -356,11 +357,10 @@ public void saveGraph() {
File.separator + CSV_DIRECTORY + File.separator + thermoSensor.getSensorName() +
File.separator + CSVLogger.FILE_NAME_FORMAT.format(new Date()) + "_graph.jpg"));
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "Unable to save bitmap", e);
}
}


private void setupInstruments() {
setUnit();
XAxis x = mChart.getXAxis();
Expand Down Expand Up @@ -582,15 +582,15 @@ private void initiateThermoSensor(int type) {
data = i2c.scan(null);
if (data.contains(0x39)) {
SHT21 sensorSHT21 = new SHT21(i2c, scienceLab);
sensorSHT21.selectParameter(TEMPERATURE);
sensorSHT21.setMode(SHT21.Mode.TEMPERATURE);
sensorType = 1;
} else {
CustomSnackBar.showSnackBar(getActivity().findViewById(android.R.id.content),
getString(R.string.sensor_not_connected_tls), null, null, Snackbar.LENGTH_SHORT);
sensorType = 0;
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
Log.e(TAG, "Unable to get data from sensor.", e);
}
} else {
CustomSnackBar.showSnackBar(getActivity().findViewById(android.R.id.content),
Expand Down
Loading