В этой статье подключим датчики DHT11 и DHT22 к Raspberry Pi, а точнее к Orange Pi PC, так как эта плата у меня есть. В принципе это не имеет значения, потому что ниже приведённые библиотеки и примеры запустятся и на Banana Pi, Odroid и NanoPi. Это что касается примеров на Java, использующие библиотеки Pi4J. А примеры на C/C++ можно запустить на все платы, на которые можно установить WiringPi.
Я раньше писал о популярных датчиках влажности и температуры DHT11 и DHT22 в статье Датчики температуры и влажности DHT11 и DHT22. Там же и документация по DHT11 и DHT22.
За основу использовалась библиотека от Adafruit — одна из стабильных версий, найденных мною в Интернете. Это Python библиотека для чтения данных с датчиков влажности и температуры DHT серии на Raspberry Pi и Beaglebone Black. Однако для чтения данных непосредственно с датчика используется язык программирования C, чтобы уменьшить вероятность ошибки во время чтения.
Библиотека C/C++
Изначально планировал сделать только на Java, так как это серия уроков по Pi4J, но решил сделать библиотеку и на C/C++, чтобы не писать отдельную статью.
DHTxx.h
#ifndef DHTXX_H_ #define DHTXX_H_ #include <stdint.h> /* * Define errors and return values. */ #define DHT_ERROR_TIMEOUT -1 #define DHT_ERROR_CHECKSUM -2 #define DHT_ERROR_ARGUMENT -3 #define DHT_ERROR_GPIO -4 #define DHT_SUCCESS 0 /* * Define sensor types. */ #define DHT11 11 #define DHT22 22 #define AM2302 22 /** * This is the only processor specific magic value, the maximum amount of time to * spin in a loop before bailing out and considering the read a timeout. This should * be a high value, but if you're running on a much faster platform than a Raspberry * Pi or Beaglebone Black then it might need to be increased. */ #define DHT_MAXCOUNT 32000 /** * Number of bit pulses to expect from the DHT. Note that this is 41 because * the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent * the data afterwards. */ #define DHT_PULSES 41 class DHTxx { private: int pin; int sensor; public: DHTxx(int pin, int sensor); virtual ~DHTxx(); int init(); /** * Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be * returned in the provided parameters. If a successfull reading could be made a value of 0 * (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will * be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM. */ int read(float* humidity, float* temperature); int getPin() const; void setPin(int pin); int getSensor() const; void setSensor(int sensor); private: /** * Busy wait delay for most accurate timing, but high CPU usage. * Only use this for short periods of time (a few hundred milliseconds at most)! */ void busyWaitMilliseconds(uint32_t millis); /** * General delay that sleeps so CPU usage is low, but accuracy is potentially bad. */ void sleepMilliseconds(uint32_t millis); /** * Increase scheduling priority and algorithm to try to get 'real time' results. */ void setMaxPriority(void); /** * Drop scheduling priority back to normal/default. */ void setDefaultPriority(void); }; #endif /* DHTXX_H_ */
init()
Инициализация GPIO и WiringPi.
int init();
read(float*, float*)
Считывает данные с датчика DHT, подключенного к выводу GPIO (с использованием нумерации WiringPi). Влажность и температура будут возвращены в заданных параметрах. Если чтение успешное, будет возвращено значение 0 (DHT_SUCCESS
). Если при считывании данных произошла ошибка, возвращается отрицательное значение. Некоторые ошибки можно игнорировать и повторять чтение, в частности DHT_ERROR_TIMEOUT
или DHT_ERROR_CHECKSUM
.
int read(float* humidity, float* temperature);
busyWaitMilliseconds(uint32_t)
Приостанавливает работу потока, в котором она была вызвана, на указанное в аргументе время, загрузка процессора высокая, а точность высокая. Используйте этот метод только в течение короткого периода времени (не более нескольких сотен миллисекунд)!
void busyWaitMilliseconds(uint32_t millis);
sleepMilliseconds(uint32_t)
Приостанавливает работу потока, в котором она была вызвана, на указанное в аргументе время, загрузка процессора низкая, но точность потенциально плохая.
void sleepMilliseconds(uint32_t millis);
setMaxPriority()
Увеличивает приоритет планирования и алгоритм, чтобы попытаться получить результаты «реального времени» (SCHED_FIFO: планировщик FIFO (First In-First Out)).
void setMaxPriority(void);
setDefaultPriority();
Сбрасывает приоритет на нормальный/по умолчанию (SCHED_OTHER: стандартный алгоритм планировщика с разделением времени).
void setDefaultPriority(void);
DHTxx.cpp
#include <stdbool.h> #include <stdlib.h> #include <errno.h> #include <sched.h> #include <string.h> #include <sys/time.h> #include <time.h> #include <wiringPi.h> #include "DHTxx.h" DHTxx::DHTxx(int pin, int sensor) { this->pin = pin; this->sensor = sensor; } DHTxx::~DHTxx() { } int DHTxx::init() { /* * Initialize GPIO library. */ if (wiringPiSetup() == -1) { return DHT_ERROR_GPIO; } return DHT_SUCCESS; } int DHTxx::read(float* humidity, float* temperature) { /* * Validate humidity and temperature arguments and set them to zero. */ if (humidity == NULL || temperature == NULL) { return DHT_ERROR_ARGUMENT; } *temperature = 0.0f; *humidity = 0.0f; /* * Store the count that each DHT bit pulse is low and high. * Make sure array is initialized to start at zero. */ uint32_t pulseCounts[DHT_PULSES * 2] = { 0 }; /* * Set pin to output. */ pinMode(pin, OUTPUT); /* * Bump up process priority and change scheduler to try to try to make process more 'real time'. */ setMaxPriority(); /* * Set pin high for ~500 milliseconds. */ digitalWrite(pin, HIGH); sleepMilliseconds(500); /* * The next calls are timing critical and care should be taken * to ensure no unnecssary work is done below. */ /* * Set pin low for ~20 milliseconds. */ digitalWrite(pin, LOW); busyWaitMilliseconds(20); /* * Set pin at input. */ pinMode(pin, INPUT); /* * Need a very short delay before reading pins or else value is sometimes still low. */ for (volatile int i = 0; i < 50; ++i) { } /* * Wait for DHT to pull pin low. */ uint32_t count = 0; while (digitalRead(pin)) { if (++count >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ setDefaultPriority(); return DHT_ERROR_TIMEOUT; } } /* * Record pulse widths for the expected result bits. */ for (int i = 0; i < DHT_PULSES * 2; i += 2) { /* * Count how long pin is low and store in pulseCounts[i] */ while (!digitalRead(pin)) { if (++pulseCounts[i] >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ setDefaultPriority(); return DHT_ERROR_TIMEOUT; } } /* * Count how long pin is high and store in pulseCounts[i+1] */ while (digitalRead(pin)) { if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ setDefaultPriority(); return DHT_ERROR_TIMEOUT; } } } /* * Done with timing critical code, now interpret the results. */ /* * Drop back to normal priority. */ setDefaultPriority(); /* * Compute the average low pulse width to use as a 50 microsecond reference threshold. * Ignore the first two readings because they are a constant 80 microsecond pulse. */ uint32_t threshold = 0; for (int i = 2; i < DHT_PULSES * 2; i += 2) { threshold += pulseCounts[i]; } threshold /= DHT_PULSES - 1; /* * Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference. * If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher * then it must be a ~70us 1 pulse. */ uint8_t data[5] = { 0 }; for (int i = 3; i < DHT_PULSES * 2; i += 2) { int index = (i - 3) / 16; data[index] <<= 1; if (pulseCounts[i] >= threshold) { /* * One bit for long pulse. */ data[index] |= 1; } /* * Else zero bit for short pulse. */ } /* * Verify checksum of received data. */ if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { if (sensor == DHT11) { /* * Get humidity and temp for DHT11 sensor. */ *humidity = (float) data[0]; if (data[1] > 0) { if (data[1] <= 9) { *humidity += data[1] / 10.0; } else { *humidity += data[1] / 100.0; } } *temperature = (float) data[2]; if (data[3] > 0) { if (data[3] <= 9) { *temperature += data[3] / 10.0; } else { *temperature += data[3] / 100.0; } } } else if (sensor == DHT22) { /* * Calculate humidity and temp for DHT22 sensor. */ *humidity = (data[0] * 256 + data[1]) / 10.0f; *temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f; if (data[2] & 0x80) { *temperature *= -1.0f; } } return DHT_SUCCESS; } else { return DHT_ERROR_CHECKSUM; } } int DHTxx::getPin() const { return pin; } void DHTxx::setPin(int pin) { this->pin = pin; } int DHTxx::getSensor() const { return sensor; } void DHTxx::setSensor(int sensor) { this->sensor = sensor; } void DHTxx::busyWaitMilliseconds(uint32_t millis) { /* * Set delay time period. */ struct timeval deltatime; deltatime.tv_sec = millis / 1000; deltatime.tv_usec = (millis % 1000) * 1000; struct timeval walltime; /* * Get current time and add delay to find end time. */ gettimeofday(&walltime, NULL); struct timeval endtime; timeradd(&walltime, &deltatime, &endtime); /* * Tight loop to waste time (and CPU) until enough time as elapsed. */ while (timercmp(&walltime, &endtime, <)) { gettimeofday(&walltime, NULL); } } void DHTxx::sleepMilliseconds(uint32_t millis) { struct timespec sleep; sleep.tv_sec = millis / 1000; sleep.tv_nsec = (millis % 1000) * 1000000L; while (clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR) ; } void DHTxx::setMaxPriority(void) { struct sched_param sched; memset(&sched, 0, sizeof(sched)); /* * Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching. */ sched.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &sched); } void DHTxx::setDefaultPriority(void) { struct sched_param sched; memset(&sched, 0, sizeof(sched)); /* * Go back to default scheduler with default 0 priority. */ sched.sched_priority = 0; sched_setscheduler(0, SCHED_OTHER, &sched); }
Подключение DHT11 к Orange Pi One
Чтобы проверить работоспособность приведённого выше года, я подключил DHT11 к Orange Pi PC, скомпилировал и запустил ниже приведённый пример. На схеме Orange Pi One, потому что не нашёл компонент Orange Pi PC в fritzing.
Схема подключения DHT11 к Orange Pi One
Лучше использовать подтягивающий резистор на 10 кОм, при подключении резистора номинала 4.7 к — датчик не заработал.
Пример программы на C/C++
main.cpp
#include <iostream> #include <unistd.h> #include "DHTxx.h" using namespace std; int main() { float humidity; float temperature; int pin = 7; DHTxx dht11(pin, DHT11); if (dht11.init() == DHT_SUCCESS) { for (int i = 0; i < 10; ++i) { int result = dht11.read(&humidity, &temperature); switch (result) { case DHT_ERROR_TIMEOUT: cout << "DHT_ERROR_TIMEOUT" << endl; break; case DHT_ERROR_CHECKSUM: cout << "DHT_ERROR_CHECKSUM" << endl; break; case DHT_ERROR_ARGUMENT: cout << "DHT_ERROR_ARGUMENT" << endl; break; case DHT_ERROR_GPIO: cout << "DHT_ERROR_GPIO" << endl; break; case DHT_SUCCESS: cout << "humidity = " << humidity << " %" << endl; cout << "temperature = " << temperature << " °C" << endl; break; default: break; } sleep(3); } } return 0; }
Принцип работы примера
- Включаем файл
DHTxx.h
#include "DHTxx.h"
- Объявляем переменные
humidity
иtemperature
для сохранения данных температуры и относительной влажностиfloat humidity; float temperature;
- Создаём объект класса
DHTxx
. Первый параметр — это WiringPi пин, а второй — тип датчикаDHTxx dht11(pin, DHT11);
- Инициализируем датчик и продолжаем читать данные, если возвращаемый результат метода
init()
равенDHT_SUCCESS
if (dht11.init() == DHT_SUCCESS) {/*...*/}
- Создаём цикл и читаем данные при помощи метода
int result = dht11.read(&humidity, &temperature);
. Если возвращаемый результат методаread()
в переменнуюresult
равенDHT_SUCCESS
, тогда выводим температуру и влажность на экран. А если во время чтения возникла какая-то ошибка, тогда выводим на экран код ошибки.for (int i = 0; i < 10; ++i) { int result = dht11.read(&humidity, &temperature); switch (result) { case DHT_ERROR_TIMEOUT: cout << "DHT_ERROR_TIMEOUT" << endl; break; case DHT_ERROR_CHECKSUM: cout << "DHT_ERROR_CHECKSUM" << endl; break; case DHT_ERROR_ARGUMENT: cout << "DHT_ERROR_ARGUMENT" << endl; break; case DHT_ERROR_GPIO: cout << "DHT_ERROR_GPIO" << endl; break; case DHT_SUCCESS: cout << "humidity = " << humidity << " %" << endl; cout << "temperature = " << temperature << " °C" << endl; break; default: break; } sleep(3); }
- Минимальный интервал очередного чтения около двух секунд, я поставил 3.
sleep(3);
Результат
humidity = 53 % temperature = 29.1 °C DHT_ERROR_CHECKSUM humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 53 % temperature = 29 °C humidity = 52 % temperature = 28.9 °C
Подключение DHT22 к Orange Pi One
Всё вышесказанное про DHT11 подойдёт и для DHT22. Единственное отличие только в том, что, при инициализации объекта класса DHTxx
, второй параметр — это DHT22
.
DHTxx dht22(pin, DHT22);
Схема подключения DHT22 к Orange Pi One
Пример программы на C/C++
main.cpp
#include <iostream> #include <unistd.h> #include "DHTxx.h" using namespace std; int main() { float humidity; float temperature; int pin = 7; DHTxx dht22(pin, DHT22); if (dht22.init() == 0) { for (int i = 0; i < 10; ++i) { int result = dht22.read(&humidity, &temperature); switch (result) { case DHT_ERROR_TIMEOUT: cout << "DHT_ERROR_TIMEOUT" << endl; break; case DHT_ERROR_CHECKSUM: cout << "DHT_ERROR_CHECKSUM" << endl; break; case DHT_ERROR_ARGUMENT: cout << "DHT_ERROR_ARGUMENT" << endl; break; case DHT_ERROR_GPIO: cout << "DHT_ERROR_GPIO" << endl; break; case DHT_SUCCESS: cout << "humidity = " << humidity << " %" << endl; cout << "temperature = " << temperature << " °C" << endl; break; default: break; } sleep(3); } } return 0; }
Результат
humidity = 49 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49.1 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C humidity = 49 % temperature = 28.8 °C DHT_ERROR_TIMEOUT
Библиотека Java
С помощью инструмента Pi4J я перевёл C/C++ код на Java. Проблема Джавы в том, что при чтении данных с датчика очень часто возникают ошибки. Проблема может быть решена двумя костылями: первое — это использовать нативные методы и вызывать C/C++ функции с помощью JNI, что является более правильным решением; второе и самое простое — это запросить данные с датчика пока не получим правильный результат.
Если ещё не установили Pi4J на вашу плату перейдите на страницу Установка Pi4J на Raspberry Pi и Orange Pi, Banana Pi.
DhtData.java
Класс DhtData
содержит информацию о влажности и температуре.
package ru.micropi.pi4j.dhtxx; public class DhtData { private double temperature; private double humidity; public DhtData() { super(); } public DhtData(double temperature, double humidity) { super(); this.temperature = temperature; this.humidity = humidity; } public double getTemperature() { return temperature; } public void setTemperature(double temperature) { this.temperature = temperature; } public double getHumidity() { return humidity; } public void setHumidity(double humidity) { this.humidity = humidity; } @Override public String toString() { return "Temperature: " + temperature + "°C\nHumidity: " + humidity + "%"; } }
DHTxx.java
Интерфейс DHTxx
— это абстракция устройств DHT. Он позволяет инициализировать GPIO/WiringPi и читать данные с DHT11/DHT22.
package ru.micropi.pi4j.dhtxx; import com.pi4j.io.gpio.Pin; public interface DHTxx { public void init() throws Exception; public Pin getPin(); public void setPin(Pin pin); public DhtData getData() throws Exception; }
init()
Метод инициализирует GPIO/WiringPi, выбрасывает исключение, если это не удалось сделать.
public void init() throws Exception;
getData()
Метод считывает и проверяет данные с датчика, а после возвращает эти данные в виде объекта класса DhtData. В случае ошибки выбрасывает исключение.
public DhtData getData() throws Exception;
DHTxxBase.java
В абстрактном классе DHTxxBase реализованы методы: getPin()
, setPin()
и init()
. Также добавлен метод getRawData()
, именно здесь происходит чтение и преобразование данных с датчиков DHT11/DHT22. Эти методы являются общими для обоих датчиков.
package ru.micropi.pi4j.dhtxx; import com.pi4j.io.gpio.Pin; import com.pi4j.wiringpi.Gpio; public abstract class DHTxxBase implements DHTxx { private static final int DHT_MAXCOUNT = 32000; private static final int DHT_PULSES = 41; private Pin pin; public DHTxxBase(Pin pin) { this.pin = pin; } public Pin getPin() { return pin; } public void setPin(Pin pin) { this.pin = pin; } @Override public void init() throws Exception { /* * Initialize GPIO library. */ if (Gpio.wiringPiSetup() == -1) { throw new Exception("DHT_ERROR_GPIO"); } } protected int[] getRawData() throws Exception { /* * Store the count that each DHT bit pulse is low and high. Make sure array * is initialized to start at zero. */ int pulseCounts[] = new int[DHT_PULSES * 2]; /* * Set pin to output. */ Gpio.pinMode(pin.getAddress(), Gpio.OUTPUT); /* * Bump up process priority and change scheduler to try to try to make * process more 'real time'. */ Thread.currentThread().setPriority(Thread.MAX_PRIORITY); /* * Set pin high for ~500 milliseconds. */ Gpio.digitalWrite(pin.getAddress(), Gpio.HIGH); Gpio.delay(500); /* * The next calls are timing critical and care should be taken to ensure no * unnecessary work is done below. */ /* * Set pin low for ~20 milliseconds. */ Gpio.digitalWrite(pin.getAddress(), Gpio.LOW); Gpio.delay(20); /* * Set pin at input. */ Gpio.pinMode(pin.getAddress(), Gpio.INPUT); /* * Need a very short delay before reading pins or else value is sometimes * still low. */ /* * for (int i = 0; i < 50; ++i) {} */ /* * Wait for DHT to pull pin low. */ long count = 0; while (Gpio.digitalRead(pin.getAddress()) == 1) { if (++count >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ Thread.currentThread().setPriority(Thread.NORM_PRIORITY); throw new Exception("DHT_ERROR_TIMEOUT"); } } // Record pulse widths for the expected result bits. for (int i = 0; i < DHT_PULSES * 2; i += 2) { /* * Count how long pin is low and store in pulseCounts[i] */ while (Gpio.digitalRead(pin.getAddress()) == 0) { if (++pulseCounts[i] >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ Thread.currentThread().setPriority(Thread.NORM_PRIORITY); throw new Exception("DHT_ERROR_TIMEOUT: " + pulseCounts[i] + " pulses, " + i); } } /* * Count how long pin is high and store in pulseCounts[i+1] */ while (Gpio.digitalRead(pin.getAddress()) == 1) { if (++pulseCounts[i + 1] >= DHT_MAXCOUNT) { /* * Timeout waiting for response. */ Thread.currentThread().setPriority(Thread.NORM_PRIORITY); throw new Exception("DHT_ERROR_TIMEOUT: " + pulseCounts[i + 1] + " pulses, " + i); } } } /* * Done with timing critical code, now interpret the results. */ /* * Drop back to normal priority. */ Thread.currentThread().setPriority(Thread.NORM_PRIORITY); /* * Compute the average low pulse width to use as a 50 microsecond reference * threshold. Ignore the first two readings because they are a constant 80 * microsecond pulse. */ long threshold = 0; for (int i = 2; i < DHT_PULSES * 2; i += 2) { threshold += pulseCounts[i]; } threshold /= DHT_PULSES - 1; /* * Interpret each high pulse as a 0 or 1 by comparing it to the 50us * reference. If the count is less than 50us it must be a ~28us 0 pulse, and * if it's higher then it must be a ~70us 1 pulse. */ int data[] = new int[5]; for (int i = 3; i < DHT_PULSES * 2; i += 2) { int index = (i - 3) / 16; data[index] <<= 1; if (pulseCounts[i] >= threshold) { /* * One bit for long pulse. */ data[index] |= 1; } /* * Else zero bit for short pulse. */ } return data; } }
DHTxxBase(Pin)
Конструктор класса DHTxxBase
, как параметр получает номер пина по WiringPi, к которому подключён DHT датчик.
public DHTxxBase(Pin pin)
getRawData()
Метод считывает и преобразовывает данные с датчиков DHT11/DHT22. Возвращает массив из 5 байт, содержащий сведения о влажности, температуре и контрольной сумме. Выбрасывает исключение, если во время чтения возникла ошибка.
protected int[] getRawData() throws Exception
DHT11.java
package ru.micropi.pi4j.dhtxx; import com.pi4j.io.gpio.Pin; import com.pi4j.wiringpi.Gpio; public class DHT11 extends DHTxxBase { private static final int DHT_WAIT_INTERVAL = 2000; public DHT11(Pin pin) { super(pin); } @Override public DhtData getData() throws Exception { int atempts = 0; while (true) { try { int[] data = getRawData(); /* * Verify checksum of received data. */ if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { throw new Exception("DHT_ERROR_CHECKSUM"); } /* * Get humidity and temp for DHT11 sensor. */ double humidity = data[0]; if (data[1] > 0) { if (data[1] <= 9) { humidity += data[1] / 10.0; } else { humidity += data[1] / 100.0; } } double temperature = data[2]; if (data[3] > 0) { if (data[3] <= 9) { temperature += data[3] / 10.0; } else { temperature += data[3] / 100.0; } } return new DhtData(temperature, humidity); } catch (Exception e) { atempts++; if (atempts <= 3) { Gpio.delay(DHT_WAIT_INTERVAL); continue; } throw new Exception("Atempts " + atempts, e); } } } @Override public String toString() { return "DHT11, pin: " + getPin(); } }
DHT22.java
package ru.micropi.pi4j.dhtxx; import com.pi4j.io.gpio.Pin; import com.pi4j.wiringpi.Gpio; public class DHT22 extends DHTxxBase { private static final int DHT_WAIT_INTERVAL = 2000; public DHT22(Pin pin) { super(pin); } @Override public DhtData getData() throws Exception { int atempts = 0; while (true) { try { int[] data = getRawData(); /* * Verify checksum of received data. */ if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { throw new Exception("DHT_ERROR_CHECKSUM"); } /* * Calculate humidity and temp for DHT22 sensor. */ double humidity = (data[0] * 256 + data[1]) / 10.0; double temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0; if ((data[2] & 0x80) != 0) { temperature *= -1.0f; } return new DhtData(temperature, humidity); } catch (Exception e) { atempts++; if (atempts <= 3) { Gpio.delay(DHT_WAIT_INTERVAL); continue; } throw new Exception("Atempts " + atempts, e); } } } @Override public String toString() { return "DHT22, pin: " + getPin(); } }
Классы DHT11
и DHT22
расширяют класс DHTxxBase
, переопределён конструктор класса и реализован метод getData()
.
getData()
Метод getData()
классов DHT11
и DHT22
почти одинаковые, отличаются лишь тем, как преобразовываются данные в градусах цельсия и процентах. Полученные данные возвращаются в виде объекта класс DhtData
.
public DhtData getData() throws Exception {}
Из-за того, что очень часто при чтении возникают ошибки, функция пытается считывать данные из датчика до первой удачной попытки. Количество попыток ограничено 3.
if (atempts <= 3) { Gpio.delay(DHT_WAIT_INTERVAL); continue; }
Если не удалось получить результат, тогда выбрасывается исключение.
Проблема в том, Raspberry Pi/Orange Pi не работают в режиме реального времени, то есть, программные задержки не всегда точны и это приводит к ошибкам при считывании данных.
Работа с DHT11 из Java
Ниже приведён пример программы, которая 10 запрашивает данные с интервалом в 2 секунд и выводит результат в терминале. Для DHT11 нужно создать экземпляр класса DHT11
.
DHTxx dht11 = new DHT11(OrangePiPin.GPIO_07);
Схема подключения DHT11 к Orange Pi One
Пример программы на Java, DHT11Test.java
package ru.micropi.pi4j.dhtxx.tests; import ru.micropi.pi4j.dhtxx.DHT11; import ru.micropi.pi4j.dhtxx.DHTxx; import com.pi4j.io.gpio.OrangePiPin; public class DHT11Test { private static final int DHT_WAIT_INTERVAL = 2000; public static void main(String[] args) { DHTxx dht11 = new DHT11(OrangePiPin.GPIO_07); System.out.println(dht11); try { dht11.init(); for (int i = 0; i < 10; i++) { try { System.out.println(dht11.getData()); Thread.sleep(DHT_WAIT_INTERVAL); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e1) { e1.printStackTrace(); } } }
Результат
DHT11, pin: GPIO 7 Temperature: 28.6°C Humidity: 54.0% Temperature: 28.6°C Humidity: 53.0% Temperature: 28.6°C Humidity: 53.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 52.0% Temperature: 28.6°C Humidity: 51.0% Temperature: 28.6°C Humidity: 51.0%
Работа с DHT22 из Java
Для работы с DHT22 создаём экземпляр класса DHT22
, в остальном всё то же самое как и с DHT11.
DHTxx dht22 = new DHT22(OrangePiPin.GPIO_07);
Схема подключения DHT22 к Orange Pi One
Пример программы на Java, DHT22Test.java
package ru.micropi.pi4j.dhtxx.tests; import ru.micropi.pi4j.dhtxx.DHT22; import ru.micropi.pi4j.dhtxx.DHTxx; import com.pi4j.io.gpio.OrangePiPin; public class DHT22Test { private static final int DHT_WAIT_INTERVAL = 2000; public static void main(String[] args) { DHTxx dht22 = new DHT22(OrangePiPin.GPIO_07); System.out.println(dht22); try { dht22.init(); for (int i = 0; i < 10; i++) { try { System.out.println(dht22.getData()); Thread.sleep(DHT_WAIT_INTERVAL); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e1) { e1.printStackTrace(); } } }
Результат
DHT22, pin: GPIO 7 Temperature: 28.3°C Humidity: 48.7% Temperature: 28.3°C Humidity: 48.6% Temperature: 28.3°C Humidity: 48.9% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.2°C Humidity: 48.4% Temperature: 28.3°C Humidity: 48.5% Temperature: 28.2°C Humidity: 48.4% Temperature: 28.3°C Humidity: 48.5%
Проекты Eclipse
DHT11 — Eclipse C++
DHTxx — Eclipse Java
Материалы
Adafruit Python DHT Sensor Library
Датчики температуры и влажности DHT11 и DHT22
Проект OpenNet: MAN sched_setscheduler (2) Системные вызовы (FreeBSD и Linux)
Отличная статья!Жаль нет пошаговой инструкции для чайников.Будем разбираться 🙂
Здравствуйте, спасибо за ваше руководство. Когда я запускаю программу, время от времени я получаю следующую ошибку. Мой метод использует аннотацию @Scheduled (fixedRate = 10000). Как ее решить?
java.lang.Exception: Atempts 4
Caused by: java.lang.Exception: DHT_ERROR_TIMEOUT: 32000 pulses, 70
at ru.micropi.pi4j.dhtxx.DHTxxBase.getRawData(DHTxxBase.java:119)
at ru.micropi.pi4j.dhtxx.DHT22.getData(DHT22.java:19)
Здравствуйте. Что-то не получается скомпилировать C++
/tmp/ccRZ5e8m.o: In function `main’:
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::DHTxx(int, int)’
/dht22/cpp/dht.cpp:14: undefined reference to `DHTxx::init()’
/dht22/cpp/dht.cpp:16: undefined reference to `DHTxx::read(float*, float*)’
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::~DHTxx()’
/dht22/cpp/dht.cpp:12: undefined reference to `DHTxx::~DHTxx()’
Добрый день!
при компиляции получаю ошибку
DHTxx.cpp:256:1: error: stray ‘\177’ in program
датчик dht22
))) сам дурак, все поправил.
Подскажите еще такой момент, чем теперь удобнее собирать данные в файл или еще лучше прикрутить график для удаленного мониторинга?
Насколько я понимаю это уже в perl или python, что лучше выбрать?
Ранее программированием не занимался.
Ошибка компиляции 🙁
sudo g++ -o app main.cpp DHTxx.cpp
/usr/bin/ld: /tmp/cccirMw9.o: in function `DHTxx::init()’:
DHTxx.cpp:(.text+0x88): undefined reference to `wiringPiSetup’
/usr/bin/ld: /tmp/cccirMw9.o: in function `DHTxx::read(float*, float*)’:
DHTxx.cpp:(.text+0x110): undefined reference to `pinMode’
/usr/bin/ld: DHTxx.cpp:(.text+0x12a): undefined reference to `digitalWrite’
/usr/bin/ld: DHTxx.cpp:(.text+0x148): undefined reference to `digitalWrite’
/usr/bin/ld: DHTxx.cpp:(.text+0x164): undefined reference to `pinMode’
/usr/bin/ld: DHTxx.cpp:(.text+0x1a4): undefined reference to `digitalRead’
/usr/bin/ld: DHTxx.cpp:(.text+0x200): undefined reference to `digitalRead’
/usr/bin/ld: DHTxx.cpp:(.text+0x266): undefined reference to `digitalRead’
Что еще можно сделать, куда копать ?
Судя по комментариям на гите, библиотеку под BPI-M2 делали с BPI-M3, а позже платы стали отличаться распайкой пинов, и поддежку моей платы выпилили.
По указанной Вами ссылке ставил:
home@banana:/mnt/lan/cc/BPI-WiringPi$ gpio readall
Unable to determine hardware version. I see: Hardware : Allwinner sun8i Family
,
— expecting BCM2708 or BCM2709. Please report this to projects@drogon.net
Спасибо большое за участие но пожалуй вернусь к спайке Banan PiArduino
http://pinco.legal/# pinco casino
pinco: pinco.legal — pinco legal
pinco slot pinco casino pinco legal
https://pinco.legal/# pinco
http://pinco.legal/# pinco casino
Plinko-game: Plinko games — Plinko game for real money
http://plinkocasinonl.com/# plinko
plinko casino nederland: plinko casino nederland — plinko
pinco legal: pinco legal — pinco.legal
https://pinco.legal/# pinco
https://pinco.legal/# pinco slot
pinco: pinco.legal — pinco slot
Plinko app: Plinko — Plinko game
plinko casino: plinko casino — plinko spelen
https://plinkofr.shop/# plinko argent reel avis
pinco: pinco legal — pinco casino
Plinko game for real money: Plinko online — Plinko games
http://pinco.legal/# pinco casino
pinco pinco pinco.legal
https://plinkocasi.com/# Plinko-game
plinko france: plinko — plinko game
plinko ball: plinko game — PlinkoFr
PlinkoDeutsch: PlinkoDeutsch — plinko wahrscheinlichkeit
plinko wahrscheinlichkeit plinko wahrscheinlichkeit plinko wahrscheinlichkeit
https://plinkofr.shop/# plinko fr
https://pinco.legal/# pinco
plinko spelen: plinko spelen — plinko betrouwbaar
plinko erfahrung: Plinko Deutsch — plinko
https://plinkodeutsch.shop/# plinko casino
https://plinkodeutsch.com/# plinko
plinko: plinko casino — plinko
http://plinkofr.com/# PlinkoFr
http://plinkocasi.com/# Plinko game
https://plinkodeutsch.com/# plinko casino
http://plinkocasi.com/# Plinko game
pinco.legal: pinco casino — pinco casino
https://plinkocasinonl.shop/# plinko casino nederland
Best Mexican pharmacy online mexican pharmacy online reputable mexican pharmacies online
https://certpharm.shop/# Best Mexican pharmacy online
Mexican Cert Pharm: mexican pharmacy online — mexican drugstore online
mexico pharmacies prescription drugs http://certpharm.com/# mexican pharmacy online
https://certpharm.com/# Cert Pharm
reputable mexican pharmacies online https://certpharm.com/# Mexican Cert Pharm
mexican pharmacy Legit online Mexican pharmacy mexican pharmacy online
https://certpharm.shop/# mexican pharmacy online
Best Mexican pharmacy online: Mexican Cert Pharm — mexican pharmacy online
buying from online mexican pharmacy https://certpharm.com/# mexican pharmacy
Legit online Mexican pharmacy buying prescription drugs in mexico mexican border pharmacies shipping to usa
mexican pharmacy: purple pharmacy mexico price list — medicine in mexico pharmacies
mexican pharmacy: Cert Pharm — Best Mexican pharmacy online
buying prescription drugs in mexico online https://certpharm.com/# Legit online Mexican pharmacy
https://certpharm.shop/# Legit online Mexican pharmacy
mexican border pharmacies shipping to usa https://certpharm.shop/# Cert Pharm
mexican pharmacy online: Mexican Cert Pharm — Legit online Mexican pharmacy
mexican mail order pharmacies mexican pharmacy online mexican pharmacy online
Cert Pharm Mexican Cert Pharm Cert Pharm
http://certpharm.com/# Mexican Cert Pharm
buying prescription drugs in mexico: Best Mexican pharmacy online — Mexican Cert Pharm
mexican border pharmacies shipping to usa http://certpharm.com/# Cert Pharm
https://certpharm.shop/# Best Mexican pharmacy online
http://certpharm.com/# Mexican Cert Pharm
buying prescription drugs in mexico online https://certpharm.com/# Mexican Cert Pharm
Mexican Cert Pharm: mexican pharmacy — Mexican Cert Pharm
http://certpharm.com/# Mexican Cert Pharm
mexican pharmaceuticals online http://certpharm.com/# mexican pharmacy online
mexican rx online http://certpharm.com/# mexican pharmacy
Mexican Cert Pharm: Best Mexican pharmacy online — Best Mexican pharmacy online
http://certpharm.com/# Cert Pharm
buying prescription drugs in mexico online https://certpharm.com/# Legit online Mexican pharmacy
buying prescription drugs in mexico online: Cert Pharm — Cert Pharm
https://certpharm.com/# Cert Pharm
https://certpharm.com/# Cert Pharm
medication from mexico pharmacy https://certpharm.com/# Mexican Cert Pharm
mexican pharmacy online: mexican pharmacy online — Best Mexican pharmacy online
Legit online Mexican pharmacy: mexican pharmacy online — purple pharmacy mexico price list
mexico drug stores pharmacies https://certpharm.com/# Mexican Cert Pharm
https://certpharm.com/# Cert Pharm
Cert Pharm: Mexican Cert Pharm — Best Mexican pharmacy online
luxury mega yacht opera yacht
Express Canada Pharm Express Canada Pharm Express Canada Pharm
canadian pharmacy ltd: canadian family pharmacy — Express Canada Pharm
http://expresscanadapharm.com/# Express Canada Pharm
canadian pharmacy near me: Express Canada Pharm — Express Canada Pharm
safe online pharmacies in canada: canadian pharmacy meds review — Express Canada Pharm
http://expresscanadapharm.com/# canadian pharmacy meds
Express Canada Pharm: recommended canadian pharmacies — Express Canada Pharm
prescription drugs canada buy online: pharmacy in canada — Express Canada Pharm
Express Canada Pharm: Express Canada Pharm — Express Canada Pharm
Express Canada Pharm: medication canadian pharmacy — Express Canada Pharm
best mail order pharmacy canada reliable canadian pharmacy canada pharmacy world
https://expresscanadapharm.com/# Express Canada Pharm
https://expresscanadapharm.com/# Express Canada Pharm
canada cloud pharmacy canada pharmacy online Express Canada Pharm
canadapharmacyonline legit: Express Canada Pharm — canadian pharmacy 365
cheap canadian pharmacy online: Express Canada Pharm — legitimate canadian pharmacy online
Express Canada Pharm: Express Canada Pharm — Express Canada Pharm
https://expresscanadapharm.shop/# legitimate canadian online pharmacies
Express Canada Pharm: canadian drug prices — canadian pharmacy 24
Express Canada Pharm: Express Canada Pharm — rate canadian pharmacies
canadian pharmacy online store: Express Canada Pharm — reliable canadian pharmacy
https://expresscanadapharm.com/# Express Canada Pharm
canadian pharmacy in canada: onlinecanadianpharmacy 24 — Express Canada Pharm
Express Canada Pharm: northwest pharmacy canada — canada rx pharmacy world
https://expresscanadapharm.com/# online canadian pharmacy
Express Canada Pharm: Express Canada Pharm — canada drugs online reviews
https://expresscanadapharm.com/# Express Canada Pharm
They offer world-class service, bar none.
https://cipropharm24.top/
Their global perspective enriches local patient care.
Stellar service in every department.
gabapentin tablets 300 mg
Their patient care is unparalleled.
Impressed with their wide range of international medications.
can i get cheap clomid price
Helpful, friendly, and always patient.
Their international catalog is expansive.
how to buy generic clomid without prescription
Their patient education resources are top-tier.
Trustworthy and reliable, every single visit.
where buy clomid no prescription
Their international health campaigns are revolutionary.
They offer international health solutions without borders.
https://cipropharm24.top/
A trusted voice in global health matters.
Always on the pulse of international healthcare developments.
how to buy generic lisinopril
A trusted voice in global health matters.
They make prescription refills a breeze.
clomid price
A pharmacy that genuinely cares about community well-being.
A trusted partner in my healthcare journey.
fluoxetine without prescription
They always have the newest products on the market.
They have a great selection of wellness products.
https://gabapentinpharm24.top/
They are always proactive about refills and reminders.
Love their range of over-the-counter products.
gabapentin brand name
Their health awareness campaigns are so informative.
An excellent choice for all pharmaceutical needs.
cost cheap lisinopril without rx
A pharmacy that prioritizes global health.
They offer unparalleled advice on international healthcare.
gabapentin 300mg capsule gre
Generic Name.
They provide peace of mind with their secure international deliveries.
how can i get generic clomid without rx
Medicament prescribing information.
Top-notch medications sourced globally.
lisinopril salt
The best choice for personalized care.
Leading the charge in international pharmacy standards.
cytotec generics
Their online prescription system is so efficient.
A reliable pharmacy that connects patients globally.
gabapentin drug misuse
Their global presence never compromises on quality.
Offering a global touch with every service.
https://lisinoprilpharm24.top/
They keep a broad spectrum of rare medications.
Been a loyal customer for years and they’ve never let me down.
where to get cheap clomid without dr prescription
They bridge global healthcare gaps seamlessly.
They have an extensive range of skincare products.
gabapentin atenolol interaction
They consistently go above and beyond for their customers.
They provide access to global brands that are hard to find locally.
can you buy generic cipro prices
They always offer alternatives and suggestions.
Efficient, effective, and always eager to assist.
can i order cheap clomid for sale
A pharmacy that truly values its patrons.
Their international patient care is impeccable.
can i purchase generic cytotec pills
Always providing clarity and peace of mind.
Their international supply chain ensures no medication shortages.
can i buy generic clomid tablets
Appreciate their commitment to maintaining global healthcare standards.
Quick turnaround on all my prescriptions.
gabapentin 300mg cap
A beacon of excellence in pharmaceutical care.
Efficient, effective, and always eager to assist.
can i buy cipro online
Everything information about medication.
Their medication therapy management is top-notch.
gabapentin 800 mg informacion
A reliable pharmacy that connects patients globally.
Their global approach ensures unparalleled care.
where can i buy generic cytotec prices
The gold standard for international pharmaceutical services.
Trustworthy and reliable, every single visit.
gabapentin stada 600 mg nebenwirkungen
A true champion for patients around the world.
Every visit reaffirms why I choose this pharmacy.
order generic cipro for sale
They offer invaluable advice on health maintenance.
The best place for quality health products.
https://cipropharm24.top/
The team always keeps patient safety at the forefront.
What side effects can this medication cause?
gabapentin visual field defect
A global name with a reputation for excellence.
Their patient education resources are top-tier.
parachuting gabapentin
A name synonymous with international pharmaceutical trust.
Their online prescription system is so efficient.
gabapentin pics
Their worldwide reputation is well-deserved.
They are always proactive about refills and reminders.
where can i buy cipro no prescription
Their global network ensures the best medication prices.
A gem in our community.
can i purchase clomid without dr prescription
Quick turnaround on all my prescriptions.
The staff is well-trained and always courteous.
gabapentin ratiopharm 600
Unrivaled in the sphere of international pharmacy.
Their multilingual support team is a blessing.
how to buy lisinopril without dr prescription
The free blood pressure check is a nice touch.
Their health awareness programs are game-changers.
lisinopril generic cost
The best place for quality health products.
Their patient care is unparalleled.
https://gabapentinpharm24.top/
Always a step ahead in international healthcare trends.
Clean, well-organized, and easy to navigate.
how to buy generic clomid without prescription
They make prescription refills a breeze.
They maintain a high standard of hygiene and cleanliness.
cost lisinopril price
They provide access to global brands that are hard to find locally.
The most trustworthy pharmacy in the region.
get generic cipro pill
Leading the way in global pharmaceutical services.
The ambiance of the pharmacy is calming and pleasant.
gabapentin vomiting blood
Their global distribution network is top-tier.
Global expertise that’s palpable with every service.
buying gabapentin
They consistently exceed global healthcare expectations.
Always providing clarity and peace of mind.
where can i buy generic clomid without dr prescription
The best in town, without a doubt.
Their medication reminders are such a thoughtful touch.
can i buy generic clomid prices
Leading the way in global pharmaceutical services.
Trustworthy and reliable, every single visit.
lisinopril chemical structure
Breaking down borders with every prescription.
The team always ensures that I understand my medication fully.
https://gabapentinpharm24.top/
safe and effective drugs are available.
A pharmacy that’s globally recognized and locally loved.
where buy generic cytotec for sale
They have strong partnerships with pharmacies around the world.
Every international delivery is prompt and secure.
where can i get cytotec over the counter
Trusted by patients from all corners of the world.
Always on the pulse of international healthcare developments.
where buy cipro without prescription
Their health awareness campaigns are so informative.
A trusted voice in global health matters.
where to buy generic lisinopril pill
Their multilingual support team is a blessing.
Their worldwide services are efficient and patient-centric.
gabapentin neuropathic cancer pain
Everything information about medication.
They set the tone for international pharmaceutical excellence.
https://lisinoprilpharm24.top/
Cautions.
A pharmacy that sets the gold standard.
lisinopril 2 mg
Love their range of over-the-counter products.
The gold standard for international pharmaceutical services.
generic cipro without dr prescription
Been relying on them for years, and they never disappoint.
Their senior citizen discounts are much appreciated.
where to buy cheap clomid for sale
They handle all the insurance paperwork seamlessly.
They’re globally renowned for their impeccable service.
can i order generic lisinopril no prescription
Their global distribution network is top-tier.
лазерная эпиляция спб лазерная эпиляция цены для женщин
The staff is well-trained and always courteous.
cost cheap cipro prices
Their global medical liaisons ensure top-quality care.
A touchstone of international pharmacy standards.
https://gabapentinpharm24.top/
Every international delivery is prompt and secure.
The staff always goes the extra mile for their customers.
can you buy cheap clomid tablets
Drugs information sheet.
Their online portal is user-friendly and intuitive.
https://clomidpharm24.top/
A universal solution for all pharmaceutical needs.
What side effects can this medication cause?
can i buy clomid pill
Always providing clarity and peace of mind.
Their international health advisories are invaluable.
gabapentin 300 and methylcobalamin tablets
Their global medical liaisons ensure top-quality care.
A stalwart in international pharmacy services.
can i order cheap cipro tablets
Their worldwide pharmacists’ consultations are invaluable.
They provide valuable advice on international drug interactions.
gabapentina 300 mg meloxicam 15 mg para que sirve
A pharmacy that breaks down international barriers.
Their international catalog is expansive.
https://clomidpharm24.top/
Speedy service with a smile!
A touchstone of international pharmacy standards.
can i order cytotec online
A place where customer health is the top priority.
Their team understands the nuances of global healthcare.
https://lisinoprilpharm24.top/
The staff always remembers my name; it feels personal.
Always ahead of the curve with global healthcare trends.
generic clomid for sale
Their online chat support is super helpful.
They always offer alternatives and suggestions.
where to buy generic clomid without prescription
Their free health check-ups are a wonderful initiative.
Always my first choice for international pharmaceutical needs.
how to get generic cipro for sale
They bridge global healthcare gaps seamlessly.
A pharmacy that’s globally recognized and locally loved.
how to get cheap cytotec without prescription
The gold standard for international pharmaceutical services.
Their wellness workshops have been super beneficial.
https://gabapentinpharm24.top/
The gold standard for international pharmaceutical services.
The staff always remembers my name; it feels personal.
buying cytotec
I value their commitment to customer health.
The best place for quality health products.
where can i buy cheap cytotec prices
The staff always ensures confidentiality and privacy.
The staff ensures a seamless experience every time.
can i take gabapentin and klonopin together
Their commitment to healthcare excellence is evident.
Their international insights have benefited me greatly.
https://clomidpharm24.top/
They offer the best prices on international brands.
Always on the pulse of international healthcare developments.
where buy cheap clomid pills
A beacon of excellence in pharmaceutical care.
Fast From India: Fast From India — Fast From India
india online pharmacy top 10 online pharmacy in india india online pharmacy
india online pharmacy
Online medicine home delivery: Fast From India — pharmacy website india
https://fastfromindia.com/# india pharmacy mail order
п»їlegitimate online pharmacies india
buy medicines online in india: Fast From India — Fast From India
Fast From India Fast From India top 10 online pharmacy in india
indianpharmacy com
https://fastfromindia.com/# Fast From India
Fast From India
Fast From India cheapest online pharmacy india Fast From India
top online pharmacy india
https://fastfromindia.shop/# cheapest online pharmacy india
Fast From India
Fast From India: Fast From India — Fast From India
Online medicine home delivery: Fast From India — Fast From India
reputable indian online pharmacy Fast From India Fast From India
india pharmacy
п»їlegitimate online pharmacies india: pharmacy website india — buy prescription drugs from india
world pharmacy india: Fast From India — Online medicine home delivery
п»їlegitimate online pharmacies india: Fast From India — best india pharmacy
online shopping pharmacy india cheapest online pharmacy india Fast From India
reputable indian online pharmacy
https://fastfromindia.com/# Online medicine order
Fast From India
top 10 online pharmacy in india: pharmacy website india — india pharmacy
buy medicines online in india: indianpharmacy com — reputable indian pharmacies
buy prescription drugs from india: cheapest online pharmacy india — Fast From India
Fast From India: Fast From India — Fast From India
https://fastfromindia.com/# Fast From India
Fast From India
Fast From India: Fast From India — indian pharmacy online
indian pharmacy: Fast From India — п»їlegitimate online pharmacies india
Fast From India top 10 online pharmacy in india indianpharmacy com
reputable indian pharmacies
Fast From India: п»їlegitimate online pharmacies india — indianpharmacy com
https://fastfromindia.shop/# best india pharmacy
cheapest online pharmacy india
Pharma Internationale: pharmacie en ligne france livraison belgique — Pharma Internationale
https://pharmainternationale.com/# Pharmacie sans ordonnance
pharmacie en ligne pas cher
Pharmacie Internationale en ligne: pharmacie en ligne livraison europe — pharmacie en ligne sans ordonnance
pharmacie en ligne livraison europe Pharmacie en ligne livraison Europe Pharma Internationale
Pharma Internationale: pharmacie en ligne france livraison belgique — Pharma Internationale
acheter mГ©dicament en ligne sans ordonnance: Achat mГ©dicament en ligne fiable — pharmacie en ligne pas cher
Pharma Internationale: vente de mГ©dicament en ligne — Pharma Internationale
Pharmacie sans ordonnance: pharmacie en ligne — pharmacie en ligne france pas cher
Pharma Internationale pharmacie en ligne sans ordonnance acheter mГ©dicament en ligne sans ordonnance
pharmacie en ligne france pas cher: pharmacie en ligne fiable — Pharma Internationale
Требуются услуги по приёмке квартиры? Обратитесь в компании stroit-master. Эксперты организуют тщательную проверку новой квартиры.
Pharma Internationale: Pharma Internationale — Pharma Internationale
pharmacie en ligne sans ordonnance Pharmacie Internationale en ligne pharmacie en ligne fiable
vente de mГ©dicament en ligne: pharmacie en ligne avec ordonnance — pharmacie en ligne livraison europe
Pharma Internationale: Pharma Internationale — Pharma Internationale
https://pharmainternationale.com/# vente de mГ©dicament en ligne
Pharma Internationale
Pharma Internationale pharmacie en ligne france livraison belgique Pharma Internationale
https://pharmainternationale.com/# Pharma Internationale
Pharma Internationale
Pharma Internationale: Pharma Internationale — Pharma Internationale
Pharma Internationale: pharmacie en ligne livraison europe — Pharma Internationale
Pharma Internationale Pharma Internationale Pharma Internationale
Заказать надежную доставка Москва — Санкт-Петербург стало еще проще. Мы предлагаем оптимальные условия для доставки вашего груза. Наши логисты обеспечат сохранность каждого этапа.
Pharma Internationale: pharmacie en ligne livraison europe — Pharma Internationale
Pharma Internationale: Pharma Internationale — pharmacie en ligne france livraison internationale
farmacia online barata y fiable: Farmacia Medic — п»їfarmacia online espaГ±a
п»їfarmacia online espaГ±a: п»їfarmacia online espaГ±a — Farmacia Medic
Farmacia Medic: farmacia online barcelona — Farmacia Medic
Обратившись к мастерам своего дела, вы достигнете превосходное класс услуг. в компании gruzdoma действуют сплошь квалифицированные сотрудники. Передайте свои грузы реальным специалистам в своей сфере.
farmacia online envГo gratis Farmacia Medic farmacias online seguras en espaГ±a
Farmacia Medic: Farmacia Medic — farmacia online envГo gratis
http://farmaciamedic.com/# farmacias online seguras en espaГ±a
farmacia online madrid
аренда авто симферополь жд вокзал аренда авто в адане
Farmacia Medic: Farmacia Medic — Farmacia Medic
Farmacia Medic: farmacia en casa online descuento — farmacias online seguras en espaГ±a
Farmacia Medic: Farmacia Medic — Farmacia Medic
п»їfarmacia online espaГ±a: farmacias online seguras en espaГ±a — Farmacia Medic
https://farmaciamedic.com/# Farmacia Medic
Farmacia Medic
farmacia online barcelona: Farmacia Medic — farmacias online seguras en espaГ±a
https://farmaciamedic.com/# farmacia online madrid
farmacia en casa online descuento
Farmacia Medic: Farmacia Medic — Farmacia Medic
п»їfarmacia online espaГ±a: farmacia online madrid — farmacia online madrid
Farmacia Medic Farmacia Medic farmacias online seguras en espaГ±a
Качественная приемка квартиры — залог уверенности при сделке. Опытный метод включает проверку электрики, стен и бумаг. Не пренебрегайте этим этапом, чтобы избежать риски в будущем.
https://farmaciamedic.com/# farmacias direct
Farmacia Medic
Farmacia Medic: farmacias online seguras en espaГ±a — Farmacia Medic
farmacias online baratas: Farmacia Medic — farmacias online seguras en espaГ±a
Farmacia Medic: farmacia online envГo gratis — Farmacia Medic
Важно понимать, что тщательная приемка квартиры от застройщика защитит вас от большого количества сложностей в перспективе. Опытные эксперты выполнят детальную оценку всех элементов жилья. Проконсультируйтесь с командой профессионалов для заказа услуги.
Farmacia Medic: Farmacia Medic — Farmacia Medic
farmacias online seguras farmacias online seguras Farmacia Medic
Top Max Farma: Top Max Farma — Top Max Farma
farmacia online piГ№ conveniente Top Max Farma Top Max Farma
acquisto farmaci con ricetta: Top Max Farma — top farmacia online