After my earlier blog post from today, I wanted to verify that I could read single bytes of data from other sensors on the Grove Beginner Kit for Arduino. The next target? The DHT20 sensor. According to the data sheet, I should be able to be able to request a status byte and that that value should typically be 0x18.
So I modified the code from the previous post.
Here is the communication on the I2C bus. You can see the command to the DHT20 sensor on the left and then its response on the right. The purple is the UART signal back to the PC.
And we can see, in IntelliJ, from the console, that the data comes back as expected: 0x18:
The changes to the previous code? First in main, then replacing the BMP280 files with equivalents for the DHT20.
MainClass.java
import org.firmata4j.I2CDevice;
import org.firmata4j.firmata.FirmataDevice;
import java.io.IOException;
public class MainClass {
static String USBPORT = "/dev/cu.usbserial-0001"; // TO-DO : modify based on your computer setup.
public static void main(String[] args) throws IOException, InterruptedException {
var myUSBPort = USBPORT;
var groveArduinoBoard = new FirmataDevice(myUSBPort);
groveArduinoBoard.start();
groveArduinoBoard.ensureInitializationIsDone();
// Set up the DHT20 sensor & a listener for I2C events.
I2CDevice firmataToI2CPressureSensor =
groveArduinoBoard.getI2CDevice(Dht20Token.DHT20_ADDR); // Sensor as I2C Object.
SensorI2CListener myI2CListener = new SensorI2CListener(firmataToI2CPressureSensor); // Listener setup.
firmataToI2CPressureSensor.subscribe(myI2CListener); // Subscribe to listener
Dht20 groveDht20Sensor = new Dht20(firmataToI2CPressureSensor, myI2CListener); // DHT20 specifics
// Initialize the sensor. Ask it for its ID.
groveDht20Sensor.init(); // init() method is like the SSD1306 Method.
// Shut off connection to the board.
groveArduinoBoard.stop();
}
}
Dht20.java
/* model this after the SSD1306 class by Oleg Kurbatov */
import org.firmata4j.I2CDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays;
import static java.lang.Integer.toHexString;
public class Dht20 {
private final I2CDevice theDHTdevice;
private final SensorI2CListener myI2CListener;
private static final Logger LOGGER = LoggerFactory.getLogger(Dht20.class);
/* constructor 1 */
public Dht20(I2CDevice theBMPdevice, SensorI2CListener myI2CListener) {
this.theDHTdevice = theBMPdevice;
this.myI2CListener = myI2CListener;
}
/* Initialize the Bmp280 sensor by asking for its ID. */
public void init() throws InterruptedException {
// 1. Tell the chip.
try{
theDHTdevice.tell(Dht20Token.DHT20_STATUS_ASK);
System.out.println("I2C telling...");
} catch (IOException e){
throw new RuntimeException(e);
}
// 2. Pause briefly.
Thread.sleep(1);
// 3. listen. (ask)
try {
theDHTdevice.ask((byte)1, myI2CListener);
System.out.println("I2C asking...");
} catch (IOException e) {
throw new RuntimeException(e);
}
Thread.sleep(20);
System.out.println("The DHT20 address: (after asking...): 0x" + toHexString(theDHTdevice.getAddress()));
}
/* basic I2C command method.
* Copied from SSD1306.java */
private void command (byte... commandBytes){
try{
for(int i = 0; i < commandBytes.length; i += 2){
theDHTdevice.tell(Arrays.copyOfRange(commandBytes,i,i+2));
}
}
catch (IOException e){
throw new RuntimeException(e);
}
}
}
Dht20Token.java
/* DHT20 constants for I2C communicition.
*
* Based on approach taken by Oleg Kurbatov and the SSD1306Token interface file.
*/
public interface Dht20Token {
final byte DHT20_ADDR = (byte) 0x38;
final byte DHT20_STATUS_ASK = (byte) 0x71;
}
SensorI2CListen.java
import org.firmata4j.I2CDevice;
import org.firmata4j.I2CEvent;
import org.firmata4j.I2CListener;
import java.math.BigInteger;
import java.util.Arrays;
public class SensorI2CListener implements I2CListener{
private final I2CDevice theI2CDevice;
SensorI2CListener(I2CDevice theI2CDevice){
this.theI2CDevice = theI2CDevice;
}
@Override
public void onReceive(I2CEvent theI2CEvent) {
// Print out the event details (address, data, etc.)
System.out.println("Listener reports the following information: ");
System.out.println("The event:" + theI2CEvent + ". Note: data is in base 10.");
System.out.println("the Device address: " +theI2CEvent.getDevice());
System.out.println("Event data array: " + Arrays.toString(theI2CEvent.getData()) + " in base 10.");
/* convert the byte array and print it */
String hexString = new BigInteger(1,theI2CEvent.getData()).toString(16);
System.out.println("Event data array: 0x" + hexString);
/* again, but compact */
System.out.println("Event data array: 0x" + new BigInteger(1,theI2CEvent.getData()).toString(16));
}
}
Dependencies
This code is dependant on the Firmata4j library which, in turn, requires JSSC, jSerialComm and SLF4J. All of these are packaged into a single JAR file located on GitHub. The JAR is based on the 2.3.9 release of Firmata4j, which is available on GitHub but not on Maven.
Conclusion
It works. But it needs further development to capture more useful data.
James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science Department of York University's Lassonde School, with degrees in Electrical and Mechanical Engineering from the University of Alberta and McGill University. Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth and engineering education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and he taught at the INSA Strasbourg and Hochschule Karlsruhe and wrote about his personal and professional perspectives. James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research in the public sphere. You can find him on Twitter. Originally from Québec City, he now lives in Toronto, Canada.