DIY Environment Monitoring
-
Thought I'd drop one of my current projects here. It started as just wanting a way to see what the temperature in a room is without having to have someone go check. (It's another building in a locked room few people have a key for.)
We already have lots of project cases, and also already had a Raspberry Pi. The new $5 Pi would need a network connection of some sort, so figure $10 for the networked PC ($20 if you need a power supply and memory card as well). I splurged at $13 for a combination temperature and humidity sensor. I went ahead and added a door sensor as well, it was $2. I also got a Cobbler Plus GPIO Breakout for $8 and a Perma-Proto board for $6. Total cost for me was $29. If you need a Pi as well figure ~$50 for everything. Compare that to any of the commercial offerings!
I'll post the code I use for everything here, along with references where possible. After all, that's where the real cost of these little things end up being.
It might be good to add a battery backup to it as well, which is quite easy, but I have no real need for that (if the power is out, the temperature isn't going to be getting out of control.) Adafruit makes it really easy.
-
First bit of coding here. The temperature/humidity sensor was meant for use in an Arduino, so I used a c program for it. Sourced from The Raspberry Pi Hobyis and Tutorials Point. Lots of examples of working with c and time around, but very few mention WHICH version of c (c, c++, c#, etc). Coming from code originally meant for use in an Arduino, it is just c.
This couple pages of code simply prints the date/time, temp C, temp F, humidity separated by commas (easy to grab the things out of later.)
/*************************************************** sample code for the HDC1000 Humidity & Temp Sensor by [email protected] 2015-08-28 adapted from Adafruit_HDC1000 library, license follows: Designed specifically to work with the HDC1000 sensor from Adafruit ----> https://www.adafruit.com/products/2635 These sensors use I2C to communicate, 2 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ #include <errno.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #include <wiringPi.h> #include <wiringPiI2C.h> #include <time.h> #define HDC1000_I2CADDR 0x40 #define HDC1000_TEMP 0x00 #define HDC1000_HUMID 0x01 #define HDC1000_CONFIG_MODE (1 << 12) #define HDC1000_CONFIG_RST (1 << 15) #define HDC1000_CONFIG_TRES_14 0 #define HDC1000_CONFIG_HRES_14 0 #define HDC1000_MANUFID 0xFE #define HDC1000_DEVICEID 0xFF uint16_t i2c_read16(int fd, uint8_t outbyte) { uint16_t retval; write(fd, &outbyte, 1); delay(50); read(fd, &retval, 2); return ntohs(retval); } uint32_t i2c_read32(int fd, uint8_t outbyte) { uint32_t retval; write(fd, &outbyte, 1); delay(50); read(fd, &retval, 4); return ntohl(retval); } int HDC1000_Init(uint8_t addr) { uint32_t x; int fd = wiringPiI2CSetup(addr); if (fd==-1) { printf("wiringPiI2CSetup for hdc1000 failed\n"); return -1; } // reset, and select 14 bit temp & humidity uint16_t config = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE | HDC1000_CONFIG_TRES_14 | HDC1000_CONFIG_HRES_14; write(fd, &config, 2); delay(15); x = i2c_read16(fd,HDC1000_MANUFID); if (x != 0x5449) { printf("HDC1000_MANUFID returned %4X\n",x); return -1; } x = i2c_read16(fd,HDC1000_DEVICEID); if (x != 0x1000) { printf("HDC1000_DEVICEID returned %4X\n",x); return -1; } return fd; } float HDC1000_readTemperature(int fd) { float temp = (i2c_read32(fd,HDC1000_TEMP) >> 16); temp /= 65536; temp *= 165; temp -= 40; return temp; } float HDC1000_readHumidity(int fd) { float hum = (i2c_read32(fd, HDC1000_TEMP) & 0xFFFF); hum /= 65536; hum *= 100; return hum; } int main(VOID) { int fd; float x; fd = HDC1000_Init(HDC1000_I2CADDR); if (fd==-1) { printf("HDC1000_Init failed\n"); return 0; } // Get and print local time time_t rawtime; struct tm *info; char buffer[80]; time( &rawtime ); info = localtime( &rawtime ); strftime(buffer,80,"%x %X", info); printf("%s", buffer ); // time_t t; // time(&t); // printf("%s",ctime(&t)); x = HDC1000_readTemperature(fd); printf(", %4.1f C, %4.1f F, ",x,((x*9)/5)+32); x = HDC1000_readHumidity(fd); printf("%4.1f%%\n",x); return 0; }
Slightly random question, how do I put that all in it's own scroll box? Never mind, it just happens.
-
Output of compiled c code.
tech@tempdoor-rpi ~/source $ tmphmdtime.out 07/07/16 12:47:07, 24.5 C, 76.1 F, 43.7%
-
When I first read the topic title I was going to suggest the Pi, Arduino and maybe the ESP8266 board.
Looks like you have all that covered.
Your image / video didn't display however.
-
@gjacobse How annoying, I'll try uploading it instead of just pointing to it maybe.
-
Thanks for sharing. Plan to post something about using DS18B20 with C# (or whatever language you like) during the next days.
-
BTW, my dear Travis, breadboards are meant for temporary testing, not for permanent installations
-
@thwr said in DIY Environment Monitoring:
BTW, my dear Travis, breadboards are meant for temporary testing, not for permanent installations
Yep, that's not a true breadboard tho. (I do have one I used to test things out, make sure I didn't release any of that magic electronic smoke.) The perma-proto boards have connections that act exactly like a breadboard, but everything has to be soldered into place.
-
@travisdh1 ah ok, didn't see that on the picture. Thanks for mentioning it.
-
@thwr said in DIY Environment Monitoring:
@travisdh1 ah ok, didn't see that on the picture. Thanks for mentioning it.
Yeah, picture doesn't really show it I know. Makes going between prototype and implementation much quicker.
-
And I have the door sensor working. Not doing anything real useful yet, just printing "DOOR ALARM!" and the time on the command line. It's in python tho, which means it's easily modded. No references for this one, tho I did lookup how to access the GPO pins from somewhere (lost where I got that bit, doh!)
tech@tempdoor-rpi ~/bin $ cat door.py import datetime import time import RPi.GPIO as io io.setmode(io.BCM) door_pin = 6 io.setup(door_pin, io.IN, pull_up_down=io.PUD_UP) #Activate door sensor using the pull up resistor while True: if io.input(door_pin): print ('DOOR ALARM!'), datetime.datetime.now().strftime("%H:%M %Y-%m-%d") time.sleep(0.5)
It works, tho doesn't do anything useful yet. More to come.
-
@travisdh1 said in DIY Environment Monitoring:
First bit of coding here. The temperature/humidity sensor was meant for use in an Arduino, so I used a c program for it. Sourced from The Raspberry Pi Hobyis and Tutorials Point. Lots of examples of working with c and time around, but very few mention WHICH version of c (c, c++, c#, etc). Coming from code originally meant for use in an Arduino, it is just c.
This couple pages of code simply prints the date/time, temp C, temp F, humidity separated by commas (easy to grab the things out of later.)
/*************************************************** sample code for the HDC1000 Humidity & Temp Sensor by [email protected] 2015-08-28 adapted from Adafruit_HDC1000 library, license follows: Designed specifically to work with the HDC1000 sensor from Adafruit ----> https://www.adafruit.com/products/2635 These sensors use I2C to communicate, 2 pins are required to interface Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. BSD license, all text above must be included in any redistribution ****************************************************/ #include <errno.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #include <wiringPi.h> #include <wiringPiI2C.h> #include <time.h> #define HDC1000_I2CADDR 0x40 #define HDC1000_TEMP 0x00 #define HDC1000_HUMID 0x01 #define HDC1000_CONFIG_MODE (1 << 12) #define HDC1000_CONFIG_RST (1 << 15) #define HDC1000_CONFIG_TRES_14 0 #define HDC1000_CONFIG_HRES_14 0 #define HDC1000_MANUFID 0xFE #define HDC1000_DEVICEID 0xFF uint16_t i2c_read16(int fd, uint8_t outbyte) { uint16_t retval; write(fd, &outbyte, 1); delay(50); read(fd, &retval, 2); return ntohs(retval); } uint32_t i2c_read32(int fd, uint8_t outbyte) { uint32_t retval; write(fd, &outbyte, 1); delay(50); read(fd, &retval, 4); return ntohl(retval); } int HDC1000_Init(uint8_t addr) { uint32_t x; int fd = wiringPiI2CSetup(addr); if (fd==-1) { printf("wiringPiI2CSetup for hdc1000 failed\n"); return -1; } // reset, and select 14 bit temp & humidity uint16_t config = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE | HDC1000_CONFIG_TRES_14 | HDC1000_CONFIG_HRES_14; write(fd, &config, 2); delay(15); x = i2c_read16(fd,HDC1000_MANUFID); if (x != 0x5449) { printf("HDC1000_MANUFID returned %4X\n",x); return -1; } x = i2c_read16(fd,HDC1000_DEVICEID); if (x != 0x1000) { printf("HDC1000_DEVICEID returned %4X\n",x); return -1; } return fd; } float HDC1000_readTemperature(int fd) { float temp = (i2c_read32(fd,HDC1000_TEMP) >> 16); temp /= 65536; temp *= 165; temp -= 40; return temp; } float HDC1000_readHumidity(int fd) { float hum = (i2c_read32(fd, HDC1000_TEMP) & 0xFFFF); hum /= 65536; hum *= 100; return hum; } int main(VOID) { int fd; float x; fd = HDC1000_Init(HDC1000_I2CADDR); if (fd==-1) { printf("HDC1000_Init failed\n"); return 0; } // Get and print local time time_t rawtime; struct tm *info; char buffer[80]; time( &rawtime ); info = localtime( &rawtime ); strftime(buffer,80,"%x %X", info); printf("%s", buffer ); // time_t t; // time(&t); // printf("%s",ctime(&t)); x = HDC1000_readTemperature(fd); printf(", %4.1f C, %4.1f F, ",x,((x*9)/5)+32); x = HDC1000_readHumidity(fd); printf("%4.1f%%\n",x); return 0; }
Slightly random question, how do I put that all in it's own scroll box? Never mind, it just happens.
I forgot an extremely important bit. For this code to work correctly, you need to download and install wiringPi. It's on git, and the build script just works. Once that's done, you do need to add -lwiringPi to your compiler options. So you compile with
gcc temphum.c -lwiringPi
-
Got a script to run that will log the daily average temperature for me. I think it's longer than it needs to be, but it works and I actually didn't have much trouble getting it to work once I dropped it into zsh. (zsh natively supports double float that bash does not.)
#!/bin/zsh # Calculate previous days average temperature # Get yesterday's date yesterday=$(date -d "-1 days" +%D) # Dump only yesterday's data into a file eval 'cat /var/log/temp/temp.log | grep ${yesterday} > /home/tech/bin/yesterdaylog' # Get a count of the number of records in yesterday's records # In case of a power outage it will be different num_records=$(eval "wc -l /home/tech/bin/yesterdaylog|cut -d' ' -f1") # Get the values in Farenheight from yesterday's file degF=( $(cut -d ',' -f3 /home/tech/bin/yesterdaylog) ) # Get a sum of the degF array to use in average tot=$((${(j[+])degF[*]})) # Devide tot by num_records to produce an average daily_average=$((tot/num_records)) daily_average2=$(eval "echo '$daily_average' | cut -c1-5") # Drop the output into another log file date +%D", "$daily_average2 >> /var/log/temp/dailytemp.log # Troubleshooting section. Print variables for confirmation. #echo "${yesterday}" #echo $num_records #echo $degF[1] #echo $tot #echo $daily_average2
And the root crontab now contains
*/10 * * * * /home/tech/bin/tmphmdtime.out >> /var/log/temp/temp.log 2 2 * * * /home/tech/bin/tmpavgcalc.sh
-
Just to cover all my bases, I also created a logrotate configuration file for my two new log files.
/var/log/temp/temp.log { monthly rotate 24 errors tech prerotate compress } /var/log/temp/dailytemp.log { monthly rotate 56 errors tech prerotate compress }
-
I suppose this could all be rolled up into a nice debian package, but for now I'm just going to image the sd card and call it a day.
Added /home/user/bin to the user's path in .bashrc. To get the current time/tempC/tempF/humidity I just run tmphmdtime.out (copied a.out to that in the user bin directory).
-
Temp monitoring is working great. My daily log
tech@tempdoor-rpi ~ $ tail /var/log/temp/dailytemp.log 07/11/16, 77.70 07/12/16, 72.56 07/13/16, 73.67 07/14/16, 73.14 07/15/16, 73.13 07/16/16, 72.83 07/17/16, 71.27 07/18/16, 71.45
When I went in the room last week to adjust the air conditioner and the door sensor pieces were glued together instead of the door and door frame. Need to get that glued on properly and then get it logging that as well. We have a security camera in the room as well, would be nice to grab a picture from it each time someone opens the door.
-
@travisdh1 said in DIY Environment Monitoring:
Temp monitoring is working great. My daily log
tech@tempdoor-rpi ~ $ tail /var/log/temp/dailytemp.log 07/11/16, 77.70 07/12/16, 72.56 07/13/16, 73.67 07/14/16, 73.14 07/15/16, 73.13 07/16/16, 72.83 07/17/16, 71.27 07/18/16, 71.45
When I went in the room last week to adjust the air conditioner and the door sensor pieces were glued together instead of the door and door frame. Need to get that glued on properly and then get it logging that as well. We have a security camera in the room as well, would be nice to grab a picture from it each time someone opens the door.
Easy, write a script that is monitoring an input pin. You could use a Reed switch for example. Basically a magnetic switch.
-
@thwr said in DIY Environment Monitoring:
@travisdh1 said in DIY Environment Monitoring:
Temp monitoring is working great. My daily log
tech@tempdoor-rpi ~ $ tail /var/log/temp/dailytemp.log 07/11/16, 77.70 07/12/16, 72.56 07/13/16, 73.67 07/14/16, 73.14 07/15/16, 73.13 07/16/16, 72.83 07/17/16, 71.27 07/18/16, 71.45
When I went in the room last week to adjust the air conditioner and the door sensor pieces were glued together instead of the door and door frame. Need to get that glued on properly and then get it logging that as well. We have a security camera in the room as well, would be nice to grab a picture from it each time someone opens the door.
Easy, write a script that is monitoring an input pin. You could use a Reed switch for example. Basically a magnetic switch.
Oh, the door monitor script is working great via a very small python script. Just need to get the little sucker mounted properly.
tech@tempdoor-rpi ~/bin $ cat door.py import datetime import time import RPi.GPIO as io io.setmode(io.BCM) door_pin = 6 io.setup(door_pin, io.IN, pull_up_down=io.PUD_UP) #Activate door sensor using the pull up resistor while True: if io.input(door_pin): print ('DOOR ALARM!'), datetime.datetime.now().strftime("%H:%M %Y-%m-%d") time.sleep(0.5)
-
@travisdh1 said in DIY Environment Monitoring:
@thwr said in DIY Environment Monitoring:
@travisdh1 said in DIY Environment Monitoring:
Temp monitoring is working great. My daily log
tech@tempdoor-rpi ~ $ tail /var/log/temp/dailytemp.log 07/11/16, 77.70 07/12/16, 72.56 07/13/16, 73.67 07/14/16, 73.14 07/15/16, 73.13 07/16/16, 72.83 07/17/16, 71.27 07/18/16, 71.45
When I went in the room last week to adjust the air conditioner and the door sensor pieces were glued together instead of the door and door frame. Need to get that glued on properly and then get it logging that as well. We have a security camera in the room as well, would be nice to grab a picture from it each time someone opens the door.
Easy, write a script that is monitoring an input pin. You could use a Reed switch for example. Basically a magnetic switch.
Oh, the door monitor script is working great via a very small python script. Just need to get the little sucker mounted properly.
tech@tempdoor-rpi ~/bin $ cat door.py import datetime import time import RPi.GPIO as io io.setmode(io.BCM) door_pin = 6 io.setup(door_pin, io.IN, pull_up_down=io.PUD_UP) #Activate door sensor using the pull up resistor while True: if io.input(door_pin): print ('DOOR ALARM!'), datetime.datetime.now().strftime("%H:%M %Y-%m-%d") time.sleep(0.5)
So your problem is getting an image? USB or IP cam?
-
@thwr said in DIY Environment Monitoring:
@travisdh1 said in DIY Environment Monitoring:
@thwr said in DIY Environment Monitoring:
@travisdh1 said in DIY Environment Monitoring:
Temp monitoring is working great. My daily log
tech@tempdoor-rpi ~ $ tail /var/log/temp/dailytemp.log 07/11/16, 77.70 07/12/16, 72.56 07/13/16, 73.67 07/14/16, 73.14 07/15/16, 73.13 07/16/16, 72.83 07/17/16, 71.27 07/18/16, 71.45
When I went in the room last week to adjust the air conditioner and the door sensor pieces were glued together instead of the door and door frame. Need to get that glued on properly and then get it logging that as well. We have a security camera in the room as well, would be nice to grab a picture from it each time someone opens the door.
Easy, write a script that is monitoring an input pin. You could use a Reed switch for example. Basically a magnetic switch.
Oh, the door monitor script is working great via a very small python script. Just need to get the little sucker mounted properly.
tech@tempdoor-rpi ~/bin $ cat door.py import datetime import time import RPi.GPIO as io io.setmode(io.BCM) door_pin = 6 io.setup(door_pin, io.IN, pull_up_down=io.PUD_UP) #Activate door sensor using the pull up resistor while True: if io.input(door_pin): print ('DOOR ALARM!'), datetime.datetime.now().strftime("%H:%M %Y-%m-%d") time.sleep(0.5)
So your problem is getting an image? USB or IP cam?
IP cam, cheap TrendNet TV-IP672PI. Haven't looked at the camera side yet to see how difficult that will be.