Commit de2d5ac5 authored by Nelso Jost's avatar Nelso Jost
Browse files

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 # License: BEERWARE (http://en.wikipedia.org/wiki/Beerware)
# Por Rafael Pezzi
# Centro de Tecnologia Acadêmica - UFRGS
# http://cta.if.ufrgs.br
# #
# Licença: GPL v3 # Purpose: Testing board comunication.
# #-------------------------------------------------------------------------------
# Baseado em projeto de Gilson Giuriatti from __future__ import print_function, division
# https://github.com/gilsong/labduino
from datetime import datetime
from pprint import pprint
from pylab import * import os
import time, serial, datetime import requests
import serial
ser = serial.Serial('/dev/ttyUSB0', 115200) import time
time.sleep(2) import json
import yaml
# Log de inicialização da estação
meteorologfile = open('meteorolog.log','a') def make_current_file_path(filename):
now=datetime.datetime.now() return os.path.join(os.path.abspath(os.path.dirname(__file__)), filename)
meteorologfile.write(now.strftime("%Y-%m-%d %H:%M:%S")+" - Iniciando log meteorológico\n")
class Meteorologger:
SETTINGS_FILENAME = make_current_file_path('settings.yaml')
medida = []
temperatura = [] CSV_SEP = ','
umidade_ar = [] DATA_FORMATS = {'INTEGER': int, 'FLOAT': float, 'STRING': str}
umidade_solo = []
pressao = [] SERIAL_READ_TIMEOUT = 1.5 # seconds
FIND_PORT_TIMEOUT = 2 # seconds
print "Iniciando Log da Estação Meterológica" BOARD_RESET_TIMEOUT = 2 # seconds
# Loop que realiza as medições def __init__(self):
while True: self.loadSettings()
try:
# Temperatura def _normalizePathFilename(self, key):
ser.write('t') if not os.path.dirname(self.CFG[key]):
t = float(ser.readline().replace('\r\n','')) self.CFG[key] = make_current_file_path(self.CFG[key])
except KeyboardInterrupt:
break def loadSettings(self):
with open(self.SETTINGS_FILENAME) as f:
try: self.CFG = yaml.safe_load(f)
# Umidade do ar
ser.write('u') if not self.CFG['BASE_URL'].endswith('/'):
u_ar = float(ser.readline().replace('\r\n','')) self.CFG['BASE_URL'] += '/'
except KeyboardInterrupt: self.URL = self.CFG['BASE_URL'] + 'api/board/post/rawsensordata/{}'\
break .format(self.CFG['BOARD_ID'])
try: self.SENSORS_CSV_LINE = self.CSV_SEP.join([d['nickname'] for d in
# Umidade do solo self.CFG['SENSORS']])
ser.write('s')
u_s = int(ser.readline().replace('\r\n','')) # convert raw str into normal escaped str (e.g., r'\\t' --> '\t')
except KeyboardInterrupt: self.CFG['EXPORT_CSV_SEP'] = bytes(self.CFG['EXPORT_CSV_SEP'], 'utf8')\
break .decode('unicode_escape')
try: self.SERIAL_PORTS = [p.strip() for p in self.CFG['SERIAL_PORT']
# Luminosidade .split(',')]
ser.write('l')
lum = int(ser.readline().replace('\r\n','')) self._normalizePathFilename('DATA_LOG_FILENAME')
except KeyboardInterrupt: self._normalizePathFilename('SERVER_OUTGOING_DATA_LOG_FILENAME')
break
def create_json_raw_sensor_data(self, raw_line):
try: raw_sensor_data = {'datetime': datetime.now().strftime("%Y%m%d%H%M%S"),
# Pressão 'sensors': {}}
ser.write('p')
pressao = int(ser.readline().replace('\r\n','')) for i, v in enumerate(raw_line.split(self.CSV_SEP)):
v = v.strip()
# Registra horário atual try:
now=datetime.datetime.now() v = self.DATA_FORMATS[self.CFG['SENSORS'][i]['data_format']](v)
except:
# Arquivo de log v = 'NaN'
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 raw_sensor_data['sensors'][self.CFG['SENSORS'][i]['nickname']] = v
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() print("\nJSON raw sensor data:")
# Aguarda para iniciar outra medida pprint(raw_sensor_data)
time.sleep(59)
except KeyboardInterrupt: return raw_sensor_data
break
def add_data_log(self, json_data):
csv_line = json_data['datetime'] + self.CFG['EXPORT_CSV_SEP']
ser.close(); 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