Skip to content

Instantly share code, notes, and snippets.

@sorz
Last active July 14, 2021 16:46
Show Gist options
  • Save sorz/a3bf0b4fe3149fb619e7 to your computer and use it in GitHub Desktop.
Save sorz/a3bf0b4fe3149fb619e7 to your computer and use it in GitHub Desktop.
All files related to a toy air temp/humi/dust mointor based on DHT22, GP2Y1010AU0F, Arduino and Cubieboard (or Raspberry Pi).
[Unit]
Description=Redraw air graphs.
[Timer]
OnBootSec=3min
OnUnitActiveSec=1h
[email protected]
[Install]
WantedBy=multi-user.target
[Unit]
Description=Redraw air graphs.
[Timer]
OnBootSec=3min
OnUnitActiveSec=1d
[email protected]
[Install]
WantedBy=multi-user.target
[Unit]
Description=Redraw air graphs.
[Timer]
OnBootSec=3min
OnUnitActiveSec=3h
[email protected]
[Install]
WantedBy=multi-user.target
[Unit]
Description=Execute a script to (re)draw RRD graphs once.
[Service]
Type=simple
User=xierch
Group=xierch
ExecStart=/home/xierch/arduino/graph.sh %i
#!/usr/bin/env python3
from serial import Serial
import subprocess
RRDTOOL = '/usr/bin/rrdtool'
DATAFILE = '/home/xierch/arduino/data.rrd'
FORMAT = 'N:%d:%.1f:%d'
def readline(serial):
line = serial.readline().decode().strip()
return line
def read_block(serial):
line = readline(serial)
assert line == 'Dust'
dust = int(readline(serial))
line = readline(serial)
assert line == 'Temp'
temp = float(readline(serial))
line = readline(serial)
assert line == 'Humi'
humi = float(readline(serial))
humi = round(humi)
handle_points(dust, temp, humi)
def handle_points(dust, temp, humi):
print('%dmg %.1fC %d%%' % (dust, temp, humi))
args = FORMAT % (dust, temp, humi)
code = subprocess.call([RRDTOOL, 'update',
'--daemon', '/tmp/rrdcached.sock',
DATAFILE, args])
if code != 0:
print('rrdtool update failed.')
def main():
serial = Serial(2)
while True:
read_block(serial)
serial.close()
if __name__ == '__main__':
main()
/*
DHT22.cpp - Library for DHT22/DHT11 relative humidity & temperature sensor.
Created by Sorz. 2014-07-18.
*/
#include "Arduino.h"
#include "DHT22.h"
TempHumiSensor::TempHumiSensor(int pin)
{
pinMode(pin, INPUT_PULLUP);
_pin = pin;
}
byte TempHumiSensor::_getbyte()
{
byte recv = 0;
// Read eight bits. For each bit,
// 0 is 26~28μs in high, 1 is 70μs in high.
for (int i=7; i>=0; i--)
{
while (! digitalRead(_pin)); // Waiting for high.
delayMicroseconds(50);
recv |= digitalRead(_pin) << i;
while (digitalRead(_pin)); // Waiting for the end of high.
}
return recv;
}
boolean TempHumiSensor::read(float *temp, float *humi)
{
// Waits up IC.
// 1. Pulldown at least 500μs, and pullup 20~40μs by host.
// 2. Waiting for pulldown 80μs then pullup 80μs by DHT.
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
delay(10);
pinMode(_pin, INPUT_PULLUP);
delayMicroseconds(70); // (30 + 80) / 2, the middle of pulldown.
boolean low = digitalRead(_pin);
delayMicroseconds(80); // The middle of pullup.
boolean high = digitalRead(_pin);
delayMicroseconds(65); // 40 + 20 / 2, the middle of first byte lead.
if (low != LOW || high != HIGH)
{
return false;
}
// Reads and checks.
byte b[4];
byte sum = 0; // Checksum
for (int i=0; i<4; ++i)
{
b[i] = _getbyte();
sum += b[i];
}
if (sum != _getbyte())
{
return false;
}
*humi = _decode_float(b[0], b[1]);
*temp = _decode_float(b[2], b[3]);
return true;
}
float TempHumiSensor::_decode_float(byte high, byte low)
{
if (high < 128)
{
return (((word) high) << 8 | low) / 10.0;
}
else
{
return (((word) high - 128) << 8 | low) / -10.0;
}
}
/*
DHT22.h - Library for DHT22 relative humidity & temperature sensor.
Created by Sorz. 2014-07-17.
*/
#ifndef DHT22_h
#define DHT22_h
#include "Arduino.h"
class TempHumiSensor
{
public:
TempHumiSensor(int pin);
boolean read(float *temp, float *humi);
private:
int _pin;
byte _getbyte();
float _decode_float(byte high, byte low);
};
#endif
/*
GP2Y1010AU0F.cpp - Library for GP2Y1010AU0F Sharp dust sensor.
Created by Sorz. 2014-07-17.
*/
#include "Arduino.h"
#include "GP2Y1010AU0F.h"
DustySensor::DustySensor(int ledPin, int outPin)
{
pinMode(ledPin, OUTPUT);
_ledPin = ledPin;
_outPin = outPin;
}
int DustySensor::readRaw()
{
digitalWrite(_ledPin, LOW); // Switch on LED.
delayMicroseconds(280);
int val = analogRead(_outPin);
delayMicroseconds(40);
digitalWrite(_ledPin,HIGH); // Switch off LED.
delayMicroseconds(9680);
return val;
}
int DustySensor::read()
{
float volt = ((float) readRaw()) * 4.88281; // Voltage in mV.
int mass = (int) (0.172 * volt - 0.9999); // Mass of dust in μg/m^3.
return mass;
}
/*
GP2Y1010AU0F.h - Library for GP2Y1010AU0F Sharp dust sensor.
Created by Sorz. 2014-07-17.
*/
#ifndef GP2Y1010AU0F_h
#define GP2Y1010AU0F_h
#include "Arduino.h"
class DustySensor
{
public:
// ledPin - Digital pin connected to LED (#2) pin.
// outPin - Analog pin connected to Vo (#5) pin.
DustySensor(int ledPin, int outPin);
// Returns mass of dust in μg/m^3.
// The reference voltage must be 5V, otherwise the output is incorrect.
int read();
// Returns the raw value returned by analogRead().
int readRaw();
private:
int _ledPin;
int _outPin;
};
#endif
#!/bin/bash
DIR=/srv/http/home/air/graph
DATA=~/arduino/data.rrd
TIME=$1
time=$(date '+%H\:%M\:%S')
rrdtool graph $DIR/temp-$TIME.svg \
--imgformat SVG \
--start end-$TIME \
--title "Air Temperature" \
DEF:temp=$DATA:temp:AVERAGE \
VDEF:avg=temp,AVERAGE \
VDEF:max=temp,MAXIMUM \
VDEF:min=temp,MINIMUM \
VDEF:now=temp,LAST \
LINE2:temp#d85427 \
GPRINT:avg:"average\: %2.1lf℃" \
GPRINT:max:"maximum\: %2.1lf℃" \
GPRINT:min:"minimum\: %2.1lf℃" \
GPRINT:now:"current\: %2.1lf℃" \
COMMENT:"($time)"
rrdtool graph $DIR/humi-$TIME.svg \
--imgformat SVG \
--start end-$TIME \
--title "Relative Humidity" \
DEF:humi=$DATA:humi:AVERAGE \
VDEF:avg=humi,AVERAGE \
VDEF:max=humi,MAXIMUM \
VDEF:min=humi,MINIMUM \
VDEF:now=humi,LAST \
LINE2:humi#0084a4 \
GPRINT:avg:"average\: %2.0lf%%" \
GPRINT:max:"maximum\: %2.0lf%%" \
GPRINT:min:"minimum\: %2.0lf%%" \
GPRINT:now:"current\: %2.0lf%%" \
COMMENT:"($time)"
rrdtool graph $DIR/dust-$TIME.svg \
--imgformat SVG \
--start end-$TIME \
--title "Dust Density" \
DEF:dust=$DATA:dust:AVERAGE \
VDEF:avg=dust,AVERAGE \
VDEF:max=dust,MAXIMUM \
VDEF:min=dust,MINIMUM \
VDEF:now=dust,LAST \
LINE2:dust#676767 \
GPRINT:avg:"average\: %2.0lfµg/m³" \
GPRINT:max:"maximum\: %2.0lfµg/m³" \
GPRINT:min:"minimum\: %2.0lfµg/m³" \
GPRINT:now:"current\: %2.0lfµg/m³" \
COMMENT:"($time)"
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<title>Air Quality at Home</title>
<style>
body { background: lightgray; }
nav { text-align: center; color: gray; }
nav a:link, nav a:visited { color: #555; }
ul.graphs { list-style-type: none; text-align: center; }
ul.graphs li { margin-bottom: 1em; }
ul.graphs img { height: 249px; width: 641px; }
footer p { text-align: right; color: darkgray; }
</style>
</head>
<body>
<nav>Time span:
<a href="#1d">1d</a> |
<a href="#1w">1w</a> |
<a href="#1m">1m</a>
</nav>
<ul class="graphs">
<li>
<img data-name="temp" src="graph/temp-1d.svg" alt="Graph for temperature." />
</li><li>
<img data-name="humi" src="graph/humi-1d.svg" alt="Graph for humidity." />
</li><li>
<img data-name="dust" src="graph/dust-1d.svg" alt="Graph for dust density." />
</li>
</ul>
<footer>
<p>Data source: DHT22 (temperature &amp; humidity), GP2Y1010AU0F (dust).</p>
</footer>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
$(document).ready(function () {
});
$(window).on('hashchange', function() {
var time = (location.hash.replace(/^#/, "") || "1d");
$('img').each(function () {
var $img = $(this);
var src = "graph/" + $img.data('name') + "-" + time + ".svg";
console.log(src);
$img.attr('src', src);
});
});
</script>
</body>
</html>
#!/bin/bash
rrdtool create data.rrd --step 5 \
DS:dust:GAUGE:10:0:600 \
DS:temp:GAUGE:10:-40:80 \
DS:humi:GAUGE:10:0:100 \
RRA:AVERAGE:0.5:12:12960 \
RRA:AVERAGE:0.5:60:25920 \
RRA:AVERAGE:0.5:360:35040
[Unit]
Description=Run rrdupdate for air data collecting.
[Service]
Type=simple
ExecStart=/home/xierch/arduino/arduino-uart.py
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
#include "GP2Y1010AU0F.h"
#include "DHT22.h"
DustySensor dustSensor(10, 0);
TempHumiSensor tempHumiSensor(9);
void setup(){
Serial.begin(9600);
}
void loop(){
int dustVal = dustSensor.read();
Serial.println("Dust");
Serial.println(dustVal);
float temp = 0;
float humi = 0;
tempHumiSensor.read(&temp, &humi);
Serial.println("Temp");
Serial.println(temp);
Serial.println("Humi");
Serial.println(humi);
delay(3000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment