Commit de2d5ac5 authored by Nelso Jost's avatar Nelso Jost

NEW: Major refactor of v0.1 tag

parent caede546
venv/
*.pyc
datalog.csv
outgoing.json
__pycache__
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Controlador da estação meteorologica
# Por Rafael Pezzi
# Centro de Tecnologia Acadêmica - UFRGS
# http://cta.if.ufrgs.br
#
# Licença: GPL v3
#
# Baseado em projeto de Gilson Giuriatti
# https://github.com/gilsong/labduino
from pylab import *
import time, serial, datetime
ser = serial.Serial('/dev/ttyUSB0', 115200)
time.sleep(2)
# Log de inicialização da estação
meteorologfile = open('meteorolog.log','a')
now=datetime.datetime.now()
meteorologfile.write(now.strftime("%Y-%m-%d %H:%M:%S")+" - Iniciando log meteorológico\n")
medida = []
temperatura = []
umidade_ar = []
umidade_solo = []
pressao = []
print "Iniciando Log da Estação Meterológica"
# Loop que realiza as medições
while True:
try:
# Temperatura
ser.write('t')
t = float(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Umidade do ar
ser.write('u')
u_ar = float(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Umidade do solo
ser.write('s')
u_s = int(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Luminosidade
ser.write('l')
lum = int(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Pressão
ser.write('p')
pressao = int(ser.readline().replace('\r\n',''))
# Registra horário atual
now=datetime.datetime.now()
# Arquivo de log
logfile = open('logfile.log','a') # Considere o caminho completo
print now.strftime("%Y%m%d%H%M%S"),"\t", t,"\t", u_ar,"\t", u_s, "\t", pressao, "\t", lum
logfile.write(now.strftime("%Y%m%d%H%M%S")+"\t"+str(t)+"\t"+str(u_ar)+"\t"+str(u_s)+"\t"+str(pressao)+"\t"+str(lum)+'\n')
logfile.close()
# Aguarda para iniciar outra medida
time.sleep(59)
except KeyboardInterrupt:
break
ser.close();
PY := python3
all:
@ echo "USAGE:"
@ echo " make setup -- Create a Python 3 virtual environment (only need once)"
@ echo " make log -- Launch the logger (using Python 3 from make setup)"
@ echo " make clean -- remove all the generated files"
setup: installpy venv
installpy:
sudo apt-get install python3
sudo apt-get install python3-pip
sudo pip3 install virtualenv
venv:
@ echo "-------------------------------------------------------"
@ if [ ! -d "venv/" ]; then \
virtualenv -q --no-site-packages --python='${PY}' venv; \
echo "Virtualenv with ${PY} created at venv/"; \
echo "-------------------------------------------------------"; \
fi
venv/bin/pip install -r requirements.pip
@ echo "on"
@ venv/bin/pip --version
log:
@ venv/bin/python meteorolog.py
testserial:
@ venv/bin/ipython test_serial.py
clean:
rm -rf datalog.csv
rm -rf outgoing.json
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Author: Nelso G. Jost (nelsojost@gmail.com)
#
# Controlador da estação meteorologica
# Por Rafael Pezzi
# Centro de Tecnologia Acadêmica - UFRGS
# http://cta.if.ufrgs.br
# License: BEERWARE (http://en.wikipedia.org/wiki/Beerware)
#
# Licença: GPL v3
#
# Baseado em projeto de Gilson Giuriatti
# https://github.com/gilsong/labduino
from pylab import *
import time, serial, datetime
ser = serial.Serial('/dev/ttyUSB0', 115200)
time.sleep(2)
# Log de inicialização da estação
meteorologfile = open('meteorolog.log','a')
now=datetime.datetime.now()
meteorologfile.write(now.strftime("%Y-%m-%d %H:%M:%S")+" - Iniciando log meteorológico\n")
medida = []
temperatura = []
umidade_ar = []
umidade_solo = []
pressao = []
print "Iniciando Log da Estação Meterológica"
# Loop que realiza as medições
while True:
try:
# Temperatura
ser.write('t')
t = float(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Umidade do ar
ser.write('u')
u_ar = float(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Umidade do solo
ser.write('s')
u_s = int(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Luminosidade
ser.write('l')
lum = int(ser.readline().replace('\r\n',''))
except KeyboardInterrupt:
break
try:
# Pressão
ser.write('p')
pressao = int(ser.readline().replace('\r\n',''))
# Registra horário atual
now=datetime.datetime.now()
# Arquivo de log
logfile = open('logfile.log','a') # Considere o caminho completo
print now.strftime("%Y%m%d%H%M%S"),"\t", t,"\t", u_ar,"\t", u_s, "\t", pressao, "\t", lum
logfile.write(now.strftime("%Y%m%d%H%M%S")+"\t"+str(t)+"\t"+str(u_ar)+"\t"+str(u_s)+"\t"+str(pressao)+"\t"+str(lum)+'\n')
logfile.close()
# Aguarda para iniciar outra medida
time.sleep(59)
except KeyboardInterrupt:
break
ser.close();
# Purpose: Testing board comunication.
#-------------------------------------------------------------------------------
from __future__ import print_function, division
from datetime import datetime
from pprint import pprint
import os
import requests
import serial
import time
import json
import yaml
def make_current_file_path(filename):
return os.path.join(os.path.abspath(os.path.dirname(__file__)), filename)
class Meteorologger:
SETTINGS_FILENAME = make_current_file_path('settings.yaml')
CSV_SEP = ','
DATA_FORMATS = {'INTEGER': int, 'FLOAT': float, 'STRING': str}
SERIAL_READ_TIMEOUT = 1.5 # seconds
FIND_PORT_TIMEOUT = 2 # seconds
BOARD_RESET_TIMEOUT = 2 # seconds
def __init__(self):
self.loadSettings()
def _normalizePathFilename(self, key):
if not os.path.dirname(self.CFG[key]):
self.CFG[key] = make_current_file_path(self.CFG[key])
def loadSettings(self):
with open(self.SETTINGS_FILENAME) as f:
self.CFG = yaml.safe_load(f)
if not self.CFG['BASE_URL'].endswith('/'):
self.CFG['BASE_URL'] += '/'
self.URL = self.CFG['BASE_URL'] + 'api/board/post/rawsensordata/{}'\
.format(self.CFG['BOARD_ID'])
self.SENSORS_CSV_LINE = self.CSV_SEP.join([d['nickname'] for d in
self.CFG['SENSORS']])
# convert raw str into normal escaped str (e.g., r'\\t' --> '\t')
self.CFG['EXPORT_CSV_SEP'] = bytes(self.CFG['EXPORT_CSV_SEP'], 'utf8')\
.decode('unicode_escape')
self.SERIAL_PORTS = [p.strip() for p in self.CFG['SERIAL_PORT']
.split(',')]
self._normalizePathFilename('DATA_LOG_FILENAME')
self._normalizePathFilename('SERVER_OUTGOING_DATA_LOG_FILENAME')
def create_json_raw_sensor_data(self, raw_line):
raw_sensor_data = {'datetime': datetime.now().strftime("%Y%m%d%H%M%S"),
'sensors': {}}
for i, v in enumerate(raw_line.split(self.CSV_SEP)):
v = v.strip()
try:
v = self.DATA_FORMATS[self.CFG['SENSORS'][i]['data_format']](v)
except:
v = 'NaN'
raw_sensor_data['sensors'][self.CFG['SENSORS'][i]['nickname']] = v
print("\nJSON raw sensor data:")
pprint(raw_sensor_data)
return raw_sensor_data
def add_data_log(self, json_data):
csv_line = json_data['datetime'] + self.CFG['EXPORT_CSV_SEP']
for sensor in self.CFG['SENSORS']:
if sensor['nickname'] in json_data['sensors']:
csv_line += str(json_data['sensors']
[sensor['nickname']])
csv_line += self.CFG['EXPORT_CSV_SEP']
with open(self.CFG['DATA_LOG_FILENAME'], "a") as f:
f.write(csv_line[:-1] + '\n')
print("\nWrited data log onto\n {}".format(
self.CFG['DATA_LOG_FILENAME']))
def send_data_to_server(self, json_data):
print("\nSending data to the server now..", end='')
r = None
try:
if os.path.exists(self.CFG['SERVER_OUTGOING_DATA_LOG_FILENAME']):
print("\nTrying to send outgoing data first...")
with open(self.CFG['SERVER_OUTGOING_DATA_LOG_FILENAME']) as f:
for i, line in enumerate(f):
r = requests.post(self.URL, json=json.loads(line))
if r.status_code != 200:
raise Exception
print('Line {} :'.format(i), r)
os.remove(self.CFG['SERVER_OUTGOING_DATA_LOG_FILENAME'])
print("\ndone! Server data is up to date!")
r = requests.post(self.URL, json=json_data)
if r.status_code != 200:
raise Exception
except:
print("\nUnable to reach the server at\n {}".format(self.URL))
print("Request:", r)
with open(self.CFG['SERVER_OUTGOING_DATA_LOG_FILENAME'], 'a') as f:
f.write(json.dumps(json_data))
f.write('\n')
print("\nAdded to\n {}".format(
self.CFG['SERVER_OUTGOING_DATA_LOG_FILENAME']))
return
print(" done.\n ", r)
def _decode_bytes(self, raw_bytes):
result = None
try:
result = raw_bytes.decode('ascii').strip()
except:
print("Invalid bytes!")
return result
def serial_read_sensors(self, csv_nickname_list, serial_port=None):
result_line, ser = None, None
try:
if serial_port is None:
serial_port = self.SERIAL_PORTS[0]
elif isinstance(serial_port, int):
serial_port = self.SERIAL_PORTS[serial_port]
# if present, the board will be reseted
ser = serial.Serial(serial_port,
self.CFG['BAUD_RATE'],
timeout = self.SERIAL_READ_TIMEOUT,
xonxoff=True)
print(ser)
time.sleep(self.BOARD_RESET_TIMEOUT)
while bool(result_line) is False:
result = ser.write(bytes(csv_nickname_list, 'utf8'))
print("sent '{}':".format(csv_nickname_list), result)
result_line = ser.readline()
print("read: ", result_line)
result_line = self._decode_bytes(result_line)
if result_line is None:
continue
ser.close()
return result_line
except KeyboardInterrupt:
raise KeyboardInterrupt
except:
print("Unable to open serial port '{}'".format(serial_port))
return None
finally:
if ser:
ser.close()
def run(self):
serial_port = 0
try:
while True:
print('\n-----------------------------------------------------')
csv_result = self.serial_read_sensors(self.SENSORS_CSV_LINE,
serial_port=serial_port)
print("csv_result: ", csv_result, type(csv_result))
if csv_result is not None:
json_raw_data = self.create_json_raw_sensor_data(csv_result)
self.add_data_log(json_raw_data)
self.send_data_to_server(json_raw_data)
else:
if serial_port < len(self.SERIAL_PORTS) - 1:
serial_port += 1
else:
serial_port = 0
print('Trying another port..')
time.sleep(self.FIND_PORT_TIMEOUT)
continue
print('\nGoing to sleep now for {} seconds..'.format(
self.CFG['READING_INTERVAL_SECONDS']))
time.sleep(self.CFG['READING_INTERVAL_SECONDS'])
except KeyboardInterrupt:
pass
if __name__ == '__main__':
Meteorologger().run()
/***************************************************
This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp sensor
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
----> http://www.adafruit.com/products/391
----> http://www.adafruit.com/products/1603
These displays 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 "Adafruit_BMP085.h"
Adafruit_BMP085::Adafruit_BMP085() {
}
boolean Adafruit_BMP085::begin(uint8_t mode) {
if (mode > BMP085_ULTRAHIGHRES)
mode = BMP085_ULTRAHIGHRES;
oversampling = mode;
Wire.begin();
if (read8(0xD0) != 0x55) return false;
/* read calibration data */
ac1 = read16(BMP085_CAL_AC1);
ac2 = read16(BMP085_CAL_AC2);
ac3 = read16(BMP085_CAL_AC3);
ac4 = read16(BMP085_CAL_AC4);
ac5 = read16(BMP085_CAL_AC5);
ac6 = read16(BMP085_CAL_AC6);
b1 = read16(BMP085_CAL_B1);
b2 = read16(BMP085_CAL_B2);
mb = read16(BMP085_CAL_MB);
mc = read16(BMP085_CAL_MC);
md = read16(BMP085_CAL_MD);
#if (BMP085_DEBUG == 1)
Serial.print("ac1 = "); Serial.println(ac1, DEC);
Serial.print("ac2 = "); Serial.println(ac2, DEC);
Serial.print("ac3 = "); Serial.println(ac3, DEC);
Serial.print("ac4 = "); Serial.println(ac4, DEC);
Serial.print("ac5 = "); Serial.println(ac5, DEC);
Serial.print("ac6 = "); Serial.println(ac6, DEC);
Serial.print("b1 = "); Serial.println(b1, DEC);
Serial.print("b2 = "); Serial.println(b2, DEC);
Serial.print("mb = "); Serial.println(mb, DEC);
Serial.print("mc = "); Serial.println(mc, DEC);
Serial.print("md = "); Serial.println(md, DEC);
#endif
return true;
}
int32_t Adafruit_BMP085::computeB5(int32_t UT) {
int32_t X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) >> 15;
int32_t X2 = ((int32_t)mc << 11) / (X1+(int32_t)md);
return X1 + X2;
}
uint16_t Adafruit_BMP085::readRawTemperature(void) {
write8(BMP085_CONTROL, BMP085_READTEMPCMD);
delay(5);
#if BMP085_DEBUG == 1
Serial.print("Raw temp: "); Serial.println(read16(BMP085_TEMPDATA));
#endif
return read16(BMP085_TEMPDATA);
}
uint32_t Adafruit_BMP085::readRawPressure(void) {
uint32_t raw;
write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6));
if (oversampling == BMP085_ULTRALOWPOWER)
delay(5);
else if (oversampling == BMP085_STANDARD)
delay(8);
else if (oversampling == BMP085_HIGHRES)
delay(14);
else
delay(26);
raw = read16(BMP085_PRESSUREDATA);
raw <<= 8;
raw |= read8(BMP085_PRESSUREDATA+2);
raw >>= (8 - oversampling);
/* this pull broke stuff, look at it later?
if (oversampling==0) {
raw <<= 8;
raw |= read8(BMP085_PRESSUREDATA+2);
raw >>= (8 - oversampling);
}
*/
#if BMP085_DEBUG == 1
Serial.print("Raw pressure: "); Serial.println(raw);
#endif
return raw;
}
int32_t Adafruit_BMP085::readPressure(void) {
int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
uint32_t B4, B7;
UT = readRawTemperature();
UP = readRawPressure();
#if BMP085_DEBUG == 1
// use datasheet numbers!
UT = 27898;
UP = 23843;
ac6 = 23153;
ac5 = 32757;
mc = -8711;
md = 2868;
b1 = 6190;
b2 = 4;
ac3 = -14383;
ac2 = -72;
ac1 = 408;
ac4 = 32741;
oversampling = 0;
#endif
B5 = computeB5(UT);
#if BMP085_DEBUG == 1
Serial.print("X1 = "); Serial.println(X1);
Serial.print("X2 = "); Serial.println(X2);
Serial.print("B5 = "); Serial.println(B5);
#endif
// do pressure calcs
B6 = B5 - 4000;
X1 = ((int32_t)b2 * ( (B6 * B6)>>12 )) >> 11;
X2 = ((int32_t)ac2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)ac1*4 + X3) << oversampling) + 2) / 4;
#if BMP085_DEBUG == 1
Serial.print("B6 = "); Serial.println(B6);
Serial.print("X1 = "); Serial.println(X1);
Serial.print("X2 = "); Serial.println(X2);
Serial.print("B3 = "); Serial.println(B3);
#endif
X1 = ((int32_t)ac3 * B6) >> 13;
X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling );
#if BMP085_DEBUG == 1
Serial.print("X1 = "); Serial.println(X1);
Serial.print("X2 = "); Serial.println(X2);
Serial.print("B4 = "); Serial.println(B4);
Serial.print("B7 = "); Serial.println(B7);
#endif
if (B7 < 0x80000000) {
p = (B7 * 2) / B4;
} else {
p = (B7 / B4) * 2;
}
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
#if BMP085_DEBUG == 1
Serial.print("p = "); Serial.println(p);
Serial.print("X1 = "); Serial.println(X1);
Serial.print("X2 = "); Serial.println(X2);
#endif
p = p + ((X1 + X2 + (int32_t)3791)>>4);
#if BMP085_DEBUG == 1
Serial.print("p = "); Serial.println(p);
#endif
return p;
}
int32_t Adafruit_BMP085::readSealevelPressure(float altitude_meters) {
float pressure = readPressure();
return (int32_t)(pressure / pow(1.0-altitude_meters/44330, 5.255));
}
float Adafruit_BMP085::readTemperature(void) {
int32_t UT, B5; // following ds convention
float temp;
UT = readRawTemperature();
#if BMP085_DEBUG == 1
// use datasheet numbers!
UT = 27898;
ac6 = 23153;
ac5 = 32757;
mc = -8711;
md = 2868;
#endif
B5 = computeB5(UT);
temp = (B5+8) >> 4;
temp /= 10;
return temp;
}
float Adafruit_BMP085::readAltitude(float sealevelPressure) {
float altitude;
float pressure = readPressure();
altitude = 44330 * (1.0 - pow(pressure /sealevelPressure,0.1903));
return altitude;
}
/*********************************************************************/
uint8_t Adafruit_BMP085::read8(uint8_t a) {
uint8_t ret;
Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
#if (ARDUINO >= 100)
Wire.write(a); // sends register address to read from
#else
Wire.send(a); // sends register address to read from
#endif
Wire.endTransmission(); // end transmission
Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
#if (ARDUINO >= 100)
ret = Wire.read(); // receive DATA
#else
ret = Wire.receive(); // receive DATA
#endif
Wire.endTransmission(); // end transmission
return ret;
}
uint16_t Adafruit_BMP085::read16(uint8_t a) {
uint16_t ret;
Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
#if (ARDUINO >= 100)
Wire.write(a); // sends register address to read from
#else
Wire.send(a); // sends register address to read from
#endif
Wire.endTransmission(); // end transmission
Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read
#if (ARDUINO >= 100)
ret = Wire.read(); // receive DATA
ret <<= 8;
ret |= Wire.read(); // receive DATA
#else
ret = Wire.receive(); // receive DATA
ret <<= 8;
ret |= Wire.receive(); // receive DATA
#endif
Wire.endTransmission(); // end transmission
return ret;
}
void Adafruit_BMP085::write8(uint8_t a, uint8_t d) {
Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
#if (ARDUINO >= 100)
Wire.write(a); // sends register address to read from
Wire.write(d); // write data
#else
Wire.send(a); // sends register address to read from
Wire.send(d); // write data
#endif
Wire.endTransmission(); // end transmission
}
/***************************************************
This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp sensor
Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout
----> http://www.adafruit.com/products/391
----> http://www.adafruit.com/products/1603
These displays use I2C to communicate, 2 pins are required to