Added DHT22 sensor

This commit is contained in:
Eric Teunis de Boone 2017-02-26 04:13:16 +01:00
parent ec91729896
commit b231ada9dc
12 changed files with 482 additions and 170 deletions

47
README.MD Normal file
View File

@ -0,0 +1,47 @@
MpDuino
=====================
A small project to interface an Arduino Uno with an OLED display,
rotary encoder to a MPD server.
Idea is to have one script `mpduino.py` creating multiple processes to
which one can attach
From PySerial to Arduino
-------------------------
A command looks like `[ES][VTAarzxcusP].*`.
Where `S` stands for set and `E` is to echo a value. The `[VTAarzxcusP]`
part selects what to set or echo. You can use `S!.*` to echo a message
back.
| Character | Property | `.*` |
|---------------|---------------|---------------------------|
| V | Volume | number |
| T | Title | text |
| A | Artist | text |
| a | album | text |
| P | Playing | empty(false)/text(true) |
| r | repeat | empty(false)/text(true) |
| z | shuffle | empty(false)/text(true) |
| x | random | empty(false)/text(true) |
| c | consume | empty(false)/text(true) |
| u | updating | empty(false)/text(true) |
| s | single | empty(false)/text(true) |
From Arduino to PySerial instance
---------------------------------
Since the Arduino has a rotary encoder for the volume and play/pause, we
need to pass these through. Next tot this, we might reset the arduino,
without resetting the pySerial script, so we need to set all values
again.
| Character | Property |
|---------------|---------------|
| R | Reset |
| V | Volume |
| P | Pause/Play |
| t | Temperature |
| h | Humidity |

25
get_tty.py Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
# A daemon which should be able to run a script, as said by the
# connecting arduino
def get_tty(noinput = True):
# Get TTY
arduino_ports = []
while not arduino_ports:
arduino_ports = [
p.device
for p in serial.tools.list_ports.comports()
if 'Arduino' in p.description
]
if not arduino_ports:
raise IOError("No Arduino found")
if len(arduino_ports) > 1:
if noinput is True:
raise IOError("Too many Arduinos found")
else:
while tty not in arduino_ports:
tty = raw_input("Enter a tty: "+" ,".join(arduino_ports)+ ";")
else:
tty = arduino_ports[0]

33
mpduino.geany Normal file
View File

@ -0,0 +1,33 @@
[editor]
line_wrapping=false
line_break_column=72
auto_continue_multiline=true
[file_prefs]
final_new_line=true
ensure_convert_new_lines=false
strip_trailing_spaces=false
replace_tabs=false
[indentation]
indent_width=4
indent_type=1
indent_hard_tab_width=8
detect_indent=false
detect_indent_width=false
indent_mode=2
[project]
name=mpduino
base_path=/home/ericteunis/Arduino/mpduino
description=
[long line marker]
long_line_behaviour=1
long_line_column=72
[files]
current_page=0
[VTE]
last_dir=/home/ericteunis/Arduino/mpduino

View File

@ -4,20 +4,37 @@
This one gives a way of scrolling through text.
*/
#define FLASH_LINE_TICKS 3
void layout(unsigned int tick) {
void initial_layout() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0, 8);
display.println("Waiting..");
display.display();
}
void layout( unsigned int tick ) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setTextWrap(false);
if ( playing || tick % 3 ) {
if ( playing || tick % FLASH_LINE_TICKS ) {
display.setCursor(0, 0);
// First line (20)
display.print(F(" "));
if (volume < 100 ) display.print(' ');
display.print(volume);
display.print(F("% |||| "));
if (volume == 100 || volume == 0){
if (volume == 100) display.print('00');
else display.print('--');
}
else display.print(volume);
display.print(F("% "));
display.print(round(temperature));
display.print(F("C "));
display.print(round(humidity));
display.print(F("% |"));
if (repeat_bool) display.print('r');
else display.print(' ');
if (random_bool) display.print('x');
@ -30,7 +47,6 @@ void layout(unsigned int tick) {
else display.print(' ');
if (updating_bool) display.print('u');
else display.print(' ');
display.print(" ");
}
//line 2
@ -55,7 +71,14 @@ String textscroll(String text, unsigned int tick) {
int len = text.length();
String newstring = "";
if ( len < chars) return text;
if ( len < chars) {
for ( int i = len; i < chars -1; i+=2){
text = " "+text+" ";
}
if ( text.length() == chars - 1) text = text+" ";
return text;
}
text = text + " - ";
for ( int i = 0; i < chars; i++ )

View File

@ -2,13 +2,46 @@
Project to interface a screen connected to an arduino with data from a vash script.
Used as start up for a HTPC.
*/
#define BAUD 9600
#define MAIN_DELAY 500
#define DHT_DELAY 10000
// STRING Commands
#define KEY_RESET 'R'
#define KEY_READ 'E'
#define KEY_ECHO '!'
#define KEY_SET 'S'
//MPD
#define KEY_VOLUME 'V'
#define KEY_TITLE 'T'
#define KEY_ARTIST 'A'
#define KEY_ALBUM 'a'
#define KEY_REPEAT 'r'
#define KEY_SHUFFLE 'z'
#define KEY_RANDOM 'x'
#define KEY_CONSUME 'c'
#define KEY_UPDATE 'u'
#define KEY_SINGLE 's'
#define KEY_PLAYING 'P'
//Sensors
#define KEY_DHT_HUMIDITY 'h'
#define KEY_DHT_TEMPERATURE 't'
// DHT
#include <DHT.h>
#define DHTPIN 7 // what pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
// OLED thingies
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//Functionality
//Functionality
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
@ -42,16 +75,17 @@ static const unsigned char PROGMEM logo16_glcd_bmp[] =
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
// Vars
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
boolean repeat_bool = true;
boolean shuffle_bool = true;
boolean consume_bool = true;
boolean random_bool = true;
boolean updating_bool = true;
boolean single_bool = true;
boolean repeat_bool = false;
boolean shuffle_bool = false;
boolean consume_bool = false;
boolean random_bool = false;
boolean updating_bool = false;
boolean single_bool = false;
boolean playing = false;
int volume = 100;
@ -59,23 +93,29 @@ String title = " << << Title >> >> ";
String artist = " << << Artist >> >> ";
String album = " << << Album >> >> ";
float humidity = 0;
float temperature = 0;
unsigned int tick = 0;
unsigned int maxticks = 0;
void setup() {
// initialise serial
Serial.begin(9600);
Serial.begin(BAUD);
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32)
// init done
display.clearDisplay();
display.display();
delay(500);
delay(MAIN_DELAY);
initial_layout();
while(!Serial);
establishContact();
layout(tick);
calcMaxTicks();
while(!Serial);
}
void loop() {
@ -88,6 +128,7 @@ void loop() {
stringComplete = false;
}
layout(tick++);
update_sensor_readings(tick);
if ( tick > maxticks ) tick = 0;
delay(500);
delay(MAIN_DELAY);
}

29
mpduino/rot_encoder.ino Normal file
View File

@ -0,0 +1,29 @@
/* Functions to control playback */
void nextSong() {
}
void forward() {
}
void prevSong() {
}
void backward() {
}
void pause() {
}
void voldown() {
}
void volup() {
}

14
mpduino/sensors.ino Normal file
View File

@ -0,0 +1,14 @@
/*
Main function for sensors
*/
void update_sensor_readings( unsigned int tick ){
if ( tick % (DHT_DELAY / MAIN_DELAY) == 0)
{
humidity = dht.readHumidity();
temperature = dht.readTemperature();
writeDHT(humidity, temperature);
}
}

88
mpduino/serial.ino Normal file
View File

@ -0,0 +1,88 @@
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
void establishContact(){
while (Serial.available() <= 0) {
Serial.println(KEY_RESET); // send an initial string
delay(300);
}
Serial.println(KEY_RESET+KEY_RESET+KEY_RESET+KEY_RESET);
}
void setFromSerial (String inputString) {
//remove newline
inputString = inputString.substring(0, inputString.length() -1);
char operation1 = inputString.charAt(0);
String string = "";
if ( operation1 == KEY_READ ){
//Echo string like: EV means echo volume
switch ( inputString.charAt(1) ) {
case KEY_VOLUME: string = volume; break;
case KEY_TITLE: string = title; break;
case KEY_ARTIST: string = artist; break;
case KEY_ALBUM: string = album; break;
case KEY_REPEAT: string = repeat_bool; break;
case KEY_SHUFFLE: string = shuffle_bool; break;
case KEY_RANDOM: string = random_bool; break;
// case KEY_CONSUME: string = consume_bool; break;
// case KEY_UPDATE: string = updating_bool; break;
// case KEY_SINGLE: string = single_bool; break;
case KEY_PLAYING: string = playing; break;
case KEY_DHT_HUMIDITY: string = humidity; break;
case KEY_DHT_TEMPERATURE: string = temperature; break;
default: string = KEY_ECHO; break;
}
Serial.println(string);
}
else if ( operation1 == KEY_SET ){
bool success = true;
string = inputString.substring(2);
switch ( inputString.charAt(1) ) {
case KEY_VOLUME: volume = string.toInt(); break;
case KEY_TITLE: title = string; break;
case KEY_ARTIST: artist = string; break;
case KEY_ALBUM: album = string; break;
case KEY_REPEAT: repeat_bool = (string != '0'); break;
case KEY_SHUFFLE: shuffle_bool = (string != '0'); break;
case KEY_RANDOM: random_bool = (string != '0'); break;
// case KEY_CONSUME: consume_bool = (string != '0'); break;
// case KEY_UPDATE: updating_bool = (string != '0'); break;
// case KEY_SINGLE: single_bool = (string != '0'); break;
case KEY_PLAYING: playing = (string != '0'); break;
//Echo
case KEY_ECHO: Serial.println(string); break;
default: success = false; break;
}
calcMaxTicks();
Serial.println(int(success), DEC);
}
else Serial.println(-1, DEC);
}
// write to serial from arduino
void writeDHT(float humidity, float temperature){
Serial.println(KEY_DHT_HUMIDITY+String(humidity));
delay(100);
Serial.println(KEY_DHT_TEMPERATURE+String(temperature));
}

View File

@ -1,70 +0,0 @@
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
void setFromSerial (String inputString) {
//remove newline
inputString = inputString.substring(0, inputString.length() -1);
char operation1 = inputString.charAt(0);
String string = "";
if ( operation1 == 'E' ){
//Echo string like: EV means echo volume
switch ( inputString.charAt(1) ) {
case 'V': string = volume; break;
case 'T': string = title; break;
case 'A': string = artist; break;
case 'a': string = album; break;
case 'r': string = repeat_bool; break;
case 'z': string = shuffle_bool; break;
case 'x': string = random_bool; break;
case 'c': string = consume_bool; break;
case 'u': string = updating_bool; break;
case 's': string = single_bool; break;
case 'P': string = playing; break;
default: string = "!"; break;
}
Serial.println(string);
}
else if ( operation1 == 'S' ){
bool success = true;
string = inputString.substring(2);
switch ( inputString.charAt(1) ) {
case 'V': volume = string.toInt(); break;
case 'T': title = string; break;
case 'A': artist = string; break;
case 'a': album = string; break;
case 'P': playing = (string != 0); break;
case 'r': repeat_bool = (string != 0); break;
case 'z': shuffle_bool = (string != 0); break;
case 'x': random_bool = (string != 0); break;
case 'c': consume_bool = (string != 0); break;
case 'u': updating_bool = (string != 0); break;
case 's': single_bool = (string != 0); break;
//Echo
case '!': Serial.println(string); break;
default: success = false; break;
}
calcMaxTicks();
Serial.println(int(success), DEC);
}
else Serial.println(-1, DEC);
}

View File

@ -2,27 +2,57 @@ import serial
import time
class SerialMPCduino(object):
__volume = None
__progress = None
__title = None
__artist = None
__album = None
__playing = None
__repeat = None
__shuffle = None
__random = None
__single = None
__consume = None
stats = {
'volume' :None,
'title' :None,
'artist' :None,
'album' :None,
'playing' :None,
'repeat' :None,
'shuffle' :None,
'random' :None,
'consume' :None,
'updating' :None,
'single' :None
}
keys = {
'read' :'E',
'write' :'S',
'reset' :'R',
'volume' :'V',
'title' :'T',
'artist' :'A',
'album' :'a',
'playing' :'P',
'repeat' :'r',
'shuffle' :'z',
'random' :'x',
'consume' :'c',
'updating' :'u',
'single' :'s',
'humidity' :'h',
'temperature' :'t',
}
def __init__(self, tty, baud, verbose):
self.tty = tty
self.baud = baud
self.verbose = verbose
self.serial = serial.Serial(tty, baud)
time.sleep(0.2)
if (self.serial.readline().decode('ascii').strip() == self.keys['write']*4):
print("All okay")
time.sleep(0.5)
def __del__(self):
self.close()
def close(self):
self.serial = None
def setup(self):
print("Setup")
print(self.serial)
@ -37,12 +67,14 @@ class SerialMPCduino(object):
#if incoming bytes are waiting to be read from the serial input buffer
#read the bytes and convert from binary array to ASCII
string = self.serial.readline().decode('ascii')
if string != 1 and string != "\n":
print(string)
return string
def write_serial(self, string):
self.vprint("S"+string)
wait_time = 0.3 + 10 * len(string) / float(self.baud)
self.serial.write("S"+string+"\n")
self.vprint(self.keys['write']+string)
wait_time = 0.3 + 20 * (len(string)+2) / float(self.baud)
self.serial.write(self.keys['write']+string+"\n")
time.sleep(wait_time)
string = self.serial.readline().decode('ascii')
@ -50,126 +82,153 @@ class SerialMPCduino(object):
self.vprint(string)
self.vprint(self.check_serial())
self.vprint("Ready")
def read_serial(self, string):
self.serial.write("E"+string+"\n")
self.serial.write(self.keys['read']+string+"\n")
return self.serial.readline()
def read_prop(self, prop):
return self.read_serial(prop)
def write_prop(self, prop, new=None, force=False):
if force or new is not None and self.stats[prop] != new:
#write to serial
if force :
new = self.stats[prop]
self.write_serial(prop+new)
def Checker(self, varfrom, varto, string):
if varfrom == varto:
return 0
self.write_serial(string)
return 1
def write_all(self):
for prop in stats:
write_prop(prop, force=True)
return
# Percentages
#@property
#def progress(self):
# return self.read_serial("p")
#@progress.setter
#def progress(self, new):
# if self.Checker(self.__progress, new, "p"+str(new)):
# print("Progress: {}".format(new))
# self.__progress = new
### Properties
# Ints
@property
def volume(self):
return self.read_serial("V")
return read_prop('volume')
@volume.setter
def volume(self, new):
if self.Checker(self.__volume, new, "V"+str(new)):
if self.Checker(self.stats['volume'], new, self.keys['volume']+str(new)):
print("Volume: {}".format(new))
self.__volume = new
self.stats['volume'] = new
# Strings
@property
def title(self):
return self.write_serial("T")
return read_prop('title')
@title.setter
def title(self, new):
if self.Checker(self.__title, new, "T"+str(new)):
if self.Checker(self.stats['title'], new, self.keys['title']+str(new)):
print("Title: {}".format(new))
self.__title = new
self.stats['title'] = new
@property
def artist(self):
return self.write_serial("A")
return read_prop('artist')
@artist.setter
def artist(self, new):
if self.Checker(self.__artist, new, "A"+str(new)):
if self.Checker(self.stats['artist'], new, self.keys['artist']+str(new)):
print("Artist: {}".format(new))
self.__artist = new
self.stats['artist'] = new
@property
def album(self):
return self.write_serial("a")
return read_prop('album')
@album.setter
def album(self, new):
if self.Checker(self.__album, new, "a"+str(new)):
if self.Checker(self.stats['album'], new, self.keys['album']+str(new)):
print("Album: {}".format(new))
self.__album = new
self.stats['album'] = new
# Booleans
@property
def repeat(self):
return self.write_serial("r")
return read_prop('repeat')
@repeat.setter
def repeat(self, new):
if self.Checker(self.__repeat, new, "r"+str(new*1)):
if self.Checker(self.stats['repeat'], new, self.keys['repeat']+str(new*1)):
print("Repeat: {}".format(new))
self.__repeat = new
self.stats['repeat'] = new
@property
def shuffle(self):
return self.write_serial("z")
return read_prop('shuffle')
@shuffle.setter
def shuffle(self, new):
if self.Checker(self.__shuffle, new, "z"+str(new*1)):
if self.Checker(self.stats['shuffle'], new, self.keys['shuffle']+str(new*1)):
print("Shuffle: {}".format(new))
self.__shuffle = new
self.stats['shuffle'] = new
# Booleans
@property
def repeat(self):
return read_prop('repeat')
@repeat.setter
def repeat(self, new):
if self.Checker(self.stats['repeat'], new, self.keys['repeat']+str(new*1)):
print("Repeat: {}".format(new))
self.stats['repeat'] = new
@property
def shuffle(self):
return read_prop('shuffle')
@shuffle.setter
def shuffle(self, new):
if self.Checker(self.stats['shuffle'], new, self.keys['shuffle']+str(new*1)):
print("Shuffle: {}".format(new))
self.stats['shuffle'] = new
@property
def single(self):
return self.read_serial("s")
return read_prop('single')
@single.setter
def single(self, single):
if self.Checker(self.__single, new, "s"+str(new*1)):
if self.Checker(self.stats['single'], new, self.keys['single']+str(new*1)):
print("Single: {}".format(new))
self.__single = new
self.stats['single'] = new
@property
def random(self):
return self.read_serial("x")
return read_prop('random')
@random.setter
def random(self, new):
if self.Checker(self.__random, new, "x"+str(new*1)):
if self.Checker(self.stats['random'], new, self.keys['random']+str(new*1)):
print("Random: {}".format(new))
self.__random = new
self.stats['random'] = new
@property
def consume(self):
return self.read_serial("x")
return read_prop('random')
@consume.setter
def consume(self, new):
if self.Checker(self.__consume, new, "c"+str(new*1)):
if self.Checker(self.stats['consume'], new, self.keys['consume']+str(new*1)):
print("Consume: {}".format(new))
self.__consume = new
self.stats['consume'] = new
#@property
#def update(self):
# return self.read_serial("u")
#@update.setter
#def update(self, new):
# if self.Checker(self.__update, new, "u"+str(new*1)):
# print("Update: {}".format(new))
# self.__update = new
@property
def update(self):
return read_prop('updating')
@update.setter
def update(self, new):
if self.Checker(self.stats['updating'], new, self.keys['updating']+str(new*1)):
print("Update: {}".format(new))
self.stats['updating'] = new
@property
def playing(self):
return self.read_serial("P")
return read_prop('playing')
@playing.setter
def playing(self, new):
if self.Checker(self.__playing, new, "P"+str(new*1)):
if self.Checker(self.stats['playing'], new, self.keys['playing']+str(new*1)):
print("Playing: {}".format(new))
self.__playing = new
self.stats['playing'] = new

BIN
serialmpcduino.pyc Normal file

Binary file not shown.

View File

@ -2,8 +2,10 @@
from serialmpcduino import SerialMPCduino
import subprocess
import time
import warnings
import serial.tools.list_ports
tty = '/dev/ttyACM0'
tty = None
baud = 9600
verbose = 1
mpdhost = 'fatserf.thuis'
@ -15,18 +17,37 @@ album = None
volume = 0
#progress = 0
repeat = True
shuffle = True
random = True
single = True
consume = True
playing = True
repeat = 0
shuffle = 0
random = 0
single = 0
consume = 0
playing = 0
if True:
# Get TTY
arduino_ports = []
while not arduino_ports:
arduino_ports = [
p.device
for p in serial.tools.list_ports.comports()
if 'Arduino' in p.description
]
if not arduino_ports:
raise IOError("No Arduino found")
if len(arduino_ports) > 1:
if noinput is True:
raise IOError("Too many Arduinos found")
else:
while tty not in arduino_ports:
tty = raw_input("Enter a tty: "+" ,".join(arduino_ports)+ ";")
else:
tty = arduino_ports[0]
try:
ser = SerialMPCduino(tty, baud, verbose)
time.sleep(0.5)
while True:
mpctext = subprocess.check_output(['mpc', '-h', mpdhost, '-f', mpcformat])
# Parse output
@ -77,7 +98,6 @@ if True:
#print("Playing: {}".format(playing))
#raw_input("")
ser.playing = playing
ser.volume = volume
#ser.progress = progress
ser.title = title
@ -85,6 +105,9 @@ if True:
ser.album = album
ser.repeat =repeat
ser.shuffle = shuffle
ser.playing = playing
time.sleep(0.4)
subprocess.call(['mpc', '-h', mpdhost, 'idle'])# Waits for changes
time.sleep(0.5)
finally:
ser.close()