Solar powered sensor temperature/humidity sensor for <15EUR
Posted: Tue Sep 08, 2015 3:47 pm
Hi, everybody.
Not sure if someone already attempted this, but I'd like to share my experience.
I'd like to have multiple temperature probes around my house, however I have problem of getting wires to relevant places.
I wanted to use ESP8266 for communication, but that still needs power to operate.
I came up with quite simple (and cheap) solution.
I bought a rather small solar panel with 2W peak power output, connected it to TP4056 battery charger, got a 18650 battery scavenged from old laptop, ESP-01, DS1820 and finally DHT-22.
I had to do some small modifications - the charge resistor on the TP4056 module had to be de-soldered and I had to solder in a new one - bigger. I went with 4.7kOhm to get the charging current to a range between 250 and 300mA. With panel producing 6V and 2W that's around the maximum power output possible.
The ESP would waste the fully-charged 1600mA battery in a day, so I had to use the deep sleep functionality. That means I had to solder a tiny wire to post-sleep-reset-pin and connect it to reset as documented here. I also de-soldered the power led indicator as that would drain the battery and is useless for me.
Next I had to lower the resistor for the 1wire temperature sensor to 1k7 and increase the wait time to 1 second - otherwise the sensor was not able to get enough power for parasitic operation.
I am logging the voltage of the ESP, the temperature of the DS1820 and the temperature and humidity values from DHT-22 sensor to ThingSpeak server.
It works quite nice for more than a week. I had to clean the data on ThingSpeak as the logging structure (field order) was changed.
The logging interval is set to 180 seconds now.
Future improvements:
For anyone interested, here is the BoM:
However the DS1820 can be omitted as the DHT-22 can also measure temperature. But I found DS1820 to be a bit more accurate.
The current source code:
Not sure if someone already attempted this, but I'd like to share my experience.
I'd like to have multiple temperature probes around my house, however I have problem of getting wires to relevant places.
I wanted to use ESP8266 for communication, but that still needs power to operate.
I came up with quite simple (and cheap) solution.
I bought a rather small solar panel with 2W peak power output, connected it to TP4056 battery charger, got a 18650 battery scavenged from old laptop, ESP-01, DS1820 and finally DHT-22.
I had to do some small modifications - the charge resistor on the TP4056 module had to be de-soldered and I had to solder in a new one - bigger. I went with 4.7kOhm to get the charging current to a range between 250 and 300mA. With panel producing 6V and 2W that's around the maximum power output possible.
The ESP would waste the fully-charged 1600mA battery in a day, so I had to use the deep sleep functionality. That means I had to solder a tiny wire to post-sleep-reset-pin and connect it to reset as documented here. I also de-soldered the power led indicator as that would drain the battery and is useless for me.
Next I had to lower the resistor for the 1wire temperature sensor to 1k7 and increase the wait time to 1 second - otherwise the sensor was not able to get enough power for parasitic operation.
I am logging the voltage of the ESP, the temperature of the DS1820 and the temperature and humidity values from DHT-22 sensor to ThingSpeak server.
It works quite nice for more than a week. I had to clean the data on ThingSpeak as the logging structure (field order) was changed.
The logging interval is set to 180 seconds now.
Future improvements:
- create a webserver after the start with static IP and AP functionality
- allow maintenance of wifi connection data
- allow maintenance of logging frequency and ThingSpeak API key
- allow up to 8 DS1820 sensors on single ESP
- enable static IP configuration for faster measurement
- buy some small enclosure and get the module outside
- try to incorporate light sensor (I2C) and use RX/TX pins for that
For anyone interested, here is the BoM:
- ESP-01 (however, I would recommend using ESP-12 as the deep sleep is MUCH easier there), price 1.97 EUR
- Solar panel, 6V, 2W for 3.06 EUR
- TP-4056 charger for 0.52 EUR
- DS18S20 - I bought 5pcs as it was cheaper as to buy 1 (!!!) and got them for 7.62 EUR, which means 1.53 EUR per 1 piece
- DHT-22 - again I bought a pack of 2 for 6.32 EUR, which means 3.16 EUR (DHT-11 can also be used, but the accuracy of measurement of humidity will suffer)
- 18650 battery like this, I got mine for free from old laptop battery, however this is a pack of 2 so 1 would cost 2.46 EUR
- 18650 battery holder for 0.38 EUR
- resistor 1k7 and 4k7 - I got mine from resistor set like this, price is less then 0.1 EUR for both
However the DS1820 can be omitted as the DHT-22 can also measure temperature. But I found DS1820 to be a bit more accurate.
The current source code:
Code: Select all
#include <ESP8266WiFi.h>
#include <dht.h>
#include <OneWire.h>
// measuring VCC using analogue input, MUST STAY HERE!
ADC_MODE(ADC_VCC);
// constants
const char* ssid = "***********"; // use your wifi ssid
const char* password = "***********"; // use your wifi password
const char* tsAPI = "*************"; // use the API key provided by ThingSpeak when you create your own channel
const char* host = "api.thingspeak.com";
const int httpPort = 80;
const char* tsURL = "/update?api_key=";
// field1 = voltage
// field2 = DS1820 temperature
// field3 = DHT temperature
// field4 = DHT humidity
// variables for loop and measurement
// Variables for temperature
unsigned long currentMillis = 0UL; // main time-counting var
unsigned long tRunLast = 0UL; // Last time temperature measurement started (for 1wire parasite interval)
unsigned long tInt = 1000UL; // Interval for temperature measurement
unsigned long tRunLast1w = 0UL; // Last measurement of 1wire sensor
unsigned long tInt1w = 2000UL; // Interval of measurement using 1wire sensor
// (increased to 2 seconds for DHT)
unsigned long tWait = 1000UL; // Interval for 1-wire parasite power stabilization (1 sec)
// Variables for reporting
unsigned long reportRunLast = 0UL; // time of last report
unsigned long reportInt = 1000UL; // reporting attempt interval
unsigned long reportTimeout = 10000UL;// timeout for reporting - if unable to measure and send
// temperature in 10 secs, go back to deep sleep
unsigned long sleepInt = 180000UL; // sleep interval
byte stage = 0; // storing measurement stages
byte poradie1w = 0; // Storing the last measured temperature sensor ID
byte i;
byte type_s;
byte data[12];
byte addr[8];
float tempDS = -999; // last temperature measurement
float tempDHT = -999; // last temperature measurement
float humiDHT = -999; // last temperature measurement
OneWire ds(2); // on pin 2 (a 1.7K resistor is necessary)
dht DHT;
#define DHT22_PIN 0
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Starting setup");
startWifi();
}
void loop() {
currentMillis = millis();
// temperature loop - initial start
if (stage == 0 && currentMillis - tRunLast >= tInt) {
// start of temperature measurement (no measurement is running now)
getTemp1();
stage = 1;
tRunLast = currentMillis;
}
if (stage == 1 && currentMillis - tRunLast >= tInt1w) {
// defined interval for 1wire parasite power and measurement over
// we can measure the temperature now
getTemp2();
DHTread();
stage = 2;
tRunLast1w = currentMillis;
tRunLast = currentMillis;
}
if (currentMillis - reportRunLast >= reportInt && stage == 2 && wifiStat() == true) {
Serial.println("Reporting");
wifiInfo();
report();
reportRunLast = currentMillis;
stage = 3;
}
// fix for timeout in measurement/reporting - force sleep
if (currentMillis - reportRunLast >= reportTimeout) {
stage = 3;
Serial.println("Forcing sleep due to timeout");
Serial.print("Current millis: ");
Serial.println(currentMillis);
Serial.print("Report last run: ");
Serial.println(reportRunLast);
Serial.print("Report timeout: ");
Serial.println(reportTimeout);
reportRunLast = currentMillis;
}
if (stage == 3) {
Serial.println("Sleeping for " + String(sleepInt) + "ms");
ESP.deepSleep(sleepInt * 1000, WAKE_RF_DEFAULT);
}
}
void startWifi() {
Serial.println("Connecting to wifi");
Serial.print("Wifi status: ");
Serial.println(WiFi.status());
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
}
void wifiInfo() {
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
byte wifiStat() {
return (WiFi.status() == WL_CONNECTED);
}
void getTemp1() {
Serial.println("Gettemp 1 started");
if (!ds.search(addr)) {
ds.reset_search();
poradie1w = 0;
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1);
stage = 1;
tRunLast1w = millis();
}
void getTemp2() {
Serial.println("Gettemp2 started");
// the first ROM byte indicates which chip
type_s = (addr[0] == 0x10) ? 1 : 0;
ds.reset();
ds.select(addr);
ds.write(0xBE);
for (int i = 0; i < 12; i++) data[i] = ds.read();
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
tempDS = (float)raw / 16.0;
Serial.print("Temp: ");
Serial.println(tempDS);
stage = 2;
tRunLast1w = millis();
poradie1w++;
}
void report() {
Serial.print("Connecting to ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, httpPort)) {
Serial.println("Connection failed!!!");
return;
}
String url = String(tsURL) + String(tsAPI) + "&field1=" + String(ESP.getVcc() / 1000.00);
url += "&field2=" + String(tempDS) + "&field3=" + String(tempDHT) + "&field4=" + String(humiDHT);
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(100);
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("Closing connection.");
}
void DHTread() {
// READ DATA
int chk = DHT.read22(DHT22_PIN);
switch (chk)
{
case DHTLIB_OK:
tempDHT = DHT.temperature;
humiDHT = DHT.humidity;
break;
default:
Serial.println("Unknown DHT error");
break;
}
}