Skip to content
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

Unable to obtain data from DHT11 #312

Open
harlanhu opened this issue Dec 27, 2023 · 2 comments
Open

Unable to obtain data from DHT11 #312

harlanhu opened this issue Dec 27, 2023 · 2 comments

Comments

@harlanhu
Copy link
Contributor

harlanhu commented Dec 27, 2023

equipment: raspi4
os: ubuntu 23.10
pi4j version: 2.4.0

I wrote some code, hoping to get data from DHT 11, after repeated tests, unfortunately I can't get enough 40 bits of data, I think it may be because the high or low level state of 40-100μs can not be accurately obtained, I tried to use a while loop to determine the current pin state, and run the AdafruitDHT.py script, when python runs and reads out the data, Java DigitalInput.state() loops do not have a full output of the correct high and low level states.The time of a loop is about 6-10 microseconds, which is enough to get the current state of the pin.
Can you give me some possible solutions?
Thanks.

Here's my code. Call the detect method.

/**
     * The length of the data.
     */
    private static final Integer DATA_LENGTH = 40;

    /**
     * The timeout duration in nanoseconds for waiting for a signal.
     * This variable represents the duration in nanoseconds that will be used
     * when waiting for a signal. If the signal is not received within this
     * duration, the waiting process will time out.
     * It is recommended to set a reasonable and appropriate value for this
     * timeout to prevent waiting indefinitely.
     */
    private final Long waitSignalTimeOutNanos;

    /**
     * This variable represents the maximum time in nanoseconds to wait for reading data before timing out.
     */
    private final Long readDataTimeOutNanos;

    /**
     * The time duration, in milliseconds, after which the data should be sent.
     * This variable is used to specify how long to wait sending data.
     */
    private static final Long SEND_DATA_TIME_MILLIS = 20L;

    @Getter
    private Double temperature;

    @Getter
    private Double humidity;

    /**
     * A FutureTask for reading data from a source.
     */
    FutureTask<long[]> readDataTask = new FutureTask<>(this::readData);

    /**
     * The interval, in seconds, between two consecutive detections.
     */
    private final Integer detectionInterval;

    /**
     * The time of the last detection.
     */
    private LocalDateTime lastDetectionTime;

    /**
     * Indicates whether to keep the signal high.
     */
    private volatile boolean keepHighSignal = true;

    protected AbstractDhtDevice(DeviceManager deviceManager, String id, String name, IBCMEnums address, Integer detectionInterval,Long waitSignalTimeOutMicros, Long readDataTimeOutMicros) {
        super(deviceManager, id, name, address, DigitalState.HIGH, DigitalState.HIGH, PullResistance.OFF);
        waitSignalTimeOutNanos = waitSignalTimeOutMicros * 1000;
        readDataTimeOutNanos = readDataTimeOutMicros * 1000;
        this.detectionInterval = detectionInterval;
    }

    /**
     * Performs a detection of temperature and humidity using a sensor.
     *
     * @return The updated temperature and humidity information.
     */
    @SneakyThrows
    public HumitureInfo detect() {
        try {
            lock.lock();
            if (Objects.nonNull(lastDetectionTime) && lastDetectionTime.plusSeconds(detectionInterval).isAfter(LocalDateTime.now())) {
                return new HumitureInfo(temperature, humidity);
            }
            if (Objects.isNull(lastDetectionTime)) {
                TimeUnit.SECONDS.sleep(2);
            }
            // Send a start signal
            digitalOutput.on();
            new Thread(readDataTask).start();
            TimeUnit.MILLISECONDS.sleep(SEND_DATA_TIME_MILLIS);
            while (keepHighSignal) {
                Thread.onSpinWait();
            }
            digitalOutput.off();
            // Read the data
            long[] data = readDataTask.get();
            // Processing of data
            HumitureInfo humitureInfo = processData(data);
            temperature = humitureInfo.getTemperature();
            humidity = humitureInfo.getHumidity();
            lastDetectionTime = LocalDateTime.now();
            return humitureInfo;
        } finally {
            lock.unlock();
            digitalOutput.off();
        }
    }

    /**
     * Reads data from a device and returns an array of long values.
     *
     * @return an array of long values representing the read data
     * @throws DeviceException if there is a timeout while reading the data
     */
    private long[] readData() {
        try {
            long[] data = new long[40];
            int dataIndex = 0;
            long eachReadEndTime = 0;
            long nanoTimer;
            // Wait for the host level to pull up
            keepHighSignal = false;
            awaitSignalOff(SEND_DATA_TIME_MILLIS * 2000000, DigitalState.LOW);
            // Wait for the DHT to pull the level low
            awaitSignalOff(waitSignalTimeOutNanos , DigitalState.HIGH);
            // Wait for the DHT to pull the level high
            awaitSignalOff(waitSignalTimeOutNanos, DigitalState.LOW);
            // Wait for the DHT to pull the level low
            awaitSignalOff(waitSignalTimeOutNanos, DigitalState.HIGH);
            // Start reading the data
            while (dataIndex < DATA_LENGTH) {
                // 50us low level start signal
                awaitSignalOff(waitSignalTimeOutNanos, DigitalState.LOW);
                // The high level starts to read the data
                nanoTimer = System.nanoTime();
                long validTime = readDataTimeOutNanos + nanoTimer;
                while (digitalInput.state() == DigitalState.HIGH) {
                    if ((eachReadEndTime = System.nanoTime()) > validTime) {
                        throw new DeviceException("Read data time out: " + (eachReadEndTime - nanoTimer) + " ns, data size: " + dataIndex);
                    }
                }
                // Save high time
                data[dataIndex] = (eachReadEndTime - nanoTimer);
                dataIndex ++;
            }
            return data;
        } finally {
            keepHighSignal = true;
        }
    }

    /**
     * Processes the given data and returns a HumitureInfo object.
     *
     * @param data An array of long values representing the data to be processed.
     * @return A HumitureInfo object containing the processed data.
     */
    protected abstract HumitureInfo processData(long[] data);

    /**
     * Waits for the specified amount of time for the given digital state to be off.
     *
     * @param timeOutNanos the timeout period in nanoseconds
     * @param digitalState the desired digital state to wait for
     * @throws DeviceException if the digital state is not off within the timeout period
     */
    private void awaitSignalOff(long timeOutNanos, DigitalState digitalState) {
        long endTime = System.nanoTime() + timeOutNanos;
        while (digitalInput.state() == digitalState) {
            if (System.nanoTime() > endTime) {
                throw new DeviceException("Keep " + digitalState.name() + " signal time out: " + (System.nanoTime() - endTime));
            }
        }
    }

    /**
     * Converts a given number to a binary system based on the provided index.
     *
     * @param num The number to be converted.
     * @param index The index indicating the position in the binary system.
     * @return The converted number in the binary system.
     */
    protected int sysConvert(long num, int index) {
        return (int) (num * Math.pow(2, 7d - index));
    }

    @Data
    @AllArgsConstructor
    public static class HumitureInfo implements Serializable {

        private Double temperature;

        private Double humidity;
    }
@taartspi
Copy link
Collaborator

taartspi commented Dec 27, 2023

https://github.com/taartspi/pi4j-example-devices/tree/master/src/main/java/com/pi4j/devices/dht22

I believe dht 11 and 22 operate the same. My implementation may miss a few bits so i use the checksum to ensure the high order between bits were zero so unimportant. As I can’t view all your code maybe seeing all of my code will assist you. .

@FDelporte
Copy link
Member

The students who did the CrowPi implementations, also with a DHT, had a lot of issues because of the timing constraints of these devices...

This is their implementation:
https://github.com/Pi4J/pi4j-example-crowpi/blob/main/src/main/java/com/pi4j/crowpi/applications/HumiTempApp.java

As you can see in the comments of the component, they use a Linux driver:
https://github.com/Pi4J/pi4j-example-crowpi/blob/main/src/main/java/com/pi4j/crowpi/components/HumiTempComponent.java

This is implemented as part of Pi4J OS:
https://github.com/Pi4J/pi4j-os/blob/main/crowpi/resources/system/config.txt#L18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants