Nombre del fichero: Main.py
Librería utilizadas:
#Modulos Sistema
import threading
import time
# Modulos ropios
import sen_humedad
import fotoresistor
import UV
import updatorSFTP
import funCpu
import pulsador
import presionATM
import voltimetro
import lluvia
import welcome
Este es el fichero principal, es el encargado de poner en funcionamiento la medidición de todos los sensores.
Lo primero y para no ser groseros saludamos por pantalla, llamamos a la clase "welcome.getbienvenida()".
# Pantalla de bienvenida
welcome.getbienvenida()
print("")
En nuestra Aplicacion usamos Threads o Hilos para controlar el ventilador del sistema y el botón que enciende la pantalla Led.
class runfan(threading.Thread):
# Controla el ventilador de la CPU.
def __init__(self, id):
threading.Thread.__init__(self)
self.id = id
def run(self):
while True:
sem.acquire()
funCpu.fun_evaluate()
time.sleep(self.id + 30)
sem.release()
class pulsOLED(threading.Thread):
# Controla si pulsamos el boton que enciende la pantalla.
def __init__(self, id):
threading.Thread.__init__(self)
self.id = id
def run(self):
sem.acquire()
pulsador.Oled()
sem.release()
f = runfan(0)
f.start()
#
p = pulsOLED(1)
p.start()
Para el resto de sensores usamos un bucle "While True" infinito para que vayan optienendo los datos de las diferentes clases. Los datos se suben de la Raspberry al Servidor cada 10 minutos, esto es modificable en el código Python. Como podemos ver al final del texto siguiente.
while True:
print("Calculando UV")
print("------------->>>")
UV_ant = UV.calcula_UV(UV_ant)
print("Calculando Luz")
print("-------------->>>")
Luz_ant = fotoresistor.main(Luz_ant)
print("Calculando Humedad y Temperatura")
print("-------------------------------->>>")
Temp_ant, Hum_ant = sen_humedad.calcula_humedad(Temp_ant, Hum_ant)
print("Calculando Presion Atmosferica")
print("------------------------------>>>")
Pressure_ant = presionATM.main(Pressure_ant)
print("Mirando por la ventana por si llueve")
print("------------------------------------>>>")
LLuvia_ant = lluvia.Control_lluvia(LLuvia_ant)
# voltimetro.calcula_bateria()
#Subimos los ficheros al servidor cada 10 minutos
i = i+1
if i == 10:
updatorSFTP.updator()
i = 0
time.sleep(60)
Nombre del fichero: sen_humedad.py
Librería utilizadas:
#Modulos Sistema
import adafruit_dht
import datetime
import board
#Modulos Propios
import writefile
Cabe destacar como parte del código importante que estamos usando el pin D4, equivale al GPIO4 (conector 7), para conectar el sensor a la Raspberry.
dhtDevice = adafruit_dht.DHT22(board.D4)
temperature = dhtDevice.temperature
humidity = dhtDevice.humidity
Nos intersa saber en que momento hacemos la medida, siempre lo calcularemos en UTC, para evitar dudas sobre el uso horario.
#Generamos la hora
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
Finalmente sólo nos quedamos con el valor medido si hay una diferencia de ± 0,5º para la Temperatura y ± 1% para la Humedad.
if temperature>temp_ant + 0.5 or temperature < temp_ant - 0.5:
temp_ant=temperature
print ("\nTEMPERATURA")
print ("-----------")
writefile.setfile("temperatura",temp_ant)
print (utc)
print ("T ", temperature)
print("")
#Guardamos los valores solo cuando haya un cambio +-1%
if humidity>hum_ant + 1 or humidity < hum_ant - 1:
hum_ant=humidity
print ("\nHUMEDAD")
print ("-------")
writefile.setfile("humedad",hum_ant)
print (utc)
print ("H ", humidity)
print("")
return(temperature,humidity)
Nombre del fichero: funCpu.py
Librería utilizadas:
#Modulos Sistema
from time import sleep
import RPi.GPIO as GPIO
from gpiozero import CPUTemperature
import writefile
Cabe destacar como parte del código importante que estamos usando el pin D22, equivale al GPIO25, para conectar el sensor a la Raspberry. En nuestro caso el ventilador se pone en funcinamiento cuando llega a los 45,1ºC.
try:
pin = 25 # Gpio25=pin 22
maxTMP = 45.1
Se envía al método writefile.setfile, es el encargado de guardar los datos en un fichero CSV. Esta operación se repite cada 40 Segundo.
writefile.setfile("Fan", round(CPU_temp, 2))
# Read the temperature every 40 sec, increase or decrease this limit if you want
sleep(40)
Nombre del fichero: lluvia.py
Librería utilizadas:
#Modulos Sistema
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
#Modulos Propios
import writefile
Esta parte del código hace referencia al conversor MCP3008 que está conectado a la Raspberry por el pin D15, Gpio22. Esta parte es muy parecida a todos los sensores analógicos que necesita ser trasnformado su información de Analógico a Digital.
def Control_lluvia(LLuvia_ant):
lluvia_ant = LLuvia_ant
# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D22)
# create the mcp object
mcp = MCP.MCP3008(spi, cs)
Con el siguiente código evaluamos las lecturas que nos devuelve el sensor de lluvia. Evaluamos si la variable lluviasensor es igual o mayor a 1, si ocurre esto es que llueve si es menor a 1 no llueve.
try:
# En teoría debería ser 0 si llueve. Pero al usar un converso Analógico Digital no es cero nunca. Pero se acerca. De ahí que sea mayor de 1 cuando no llueve
lluviasensor = AnalogIn(mcp, MCP.P0).voltage
if (lluviasensor > 1):
print("------")
print("NO Llueve")
print("------")
lluvia = False
elif (lluviasensor >= 0.01):
print("------")
print("Llueve")
print("------")
lluvia = True
if (lluvia_ant != lluvia):
print("Cambio de Tiempo")
writefile.setfile("Lluvia", lluvia)
lluvia_ant = lluvia
Nombre del fichero: welcome.py
Librería utilizadas:
#Modulos Sistema
import datetime
import subprocess
import time
import board
import digitalio
import adafruit_ssd1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
#Modulos Propios
import obtenserial
A modo de saludo inicial cargamos una pequeña imagen de un ratón. Y a continuación durante unos segundos se puede obtenemos datos por pantalla, como la fecha, la IP y el número de serie de la Raspberry. Podemos jugar un poco para ubicar la información por pantalla usando las variables x y top. Obviamente el código no es mío, reutilicé uno que encontré por Internet.
# Load image based on OLED display height. Note that image is converted to 1 bit color.
image = Image.open('Raton_Mini_h.png').resize((oled.width, oled.height), Image.ANTIALIAS).convert('1')
[...]
cmd = "hostname -I"
IP = subprocess.check_output(cmd, shell=True)
IP = str(IP)
IP = IP[2:IP.find(' ')]
draw.text((x, top), str(datetime2.strftime("%d/%m/%Y %H:%M")) , font=font, fill=255)
draw.text((x, top + 8), obtenserial.getserial(), font=font, fill=255)
draw.text((x, top + 16), IP, font=font, fill=255)
[...]
Nombre del fichero: muestra.py
Nombre del fichero: pantalla.xml
Librería utilizadas en muestra.py
#Modulos Sistema
import xml.etree.ElementTree as ET
import os
Usamos un fichero xml llamado "pantalla.xml" para ir almacenando el último valor que va obteniendo las raspberry antes de enviar los datos a Internet. Para leer el fichero xml y mostrar la información cuando se pulsa el botón hemos creado la clase def leeXML(), se encarga de navegar por el árbol XML por cada categoría y recoger los datos y guardarlos en un array de datos.
def leeXML():
tree = ET.parse(os.getcwd()+'/pantalla.xml')
root = tree.getroot()
contenedor = []
# Lista todos los elementos
for country in root.findall('Tipo'):
valor = country.find('Valor').text
titulo = country.find('Acro').text
formato = country.find('Formato').text
contenedor.append(titulo+" "+valor + formato)
return contenedor
Con df escribeXML(...) guardamos los datos actualizados en el XML, ojo solo guardamos el último valor por cada categoria. Los anteriores desaparecen para siempre. Recordamos que solo usamos el fichero XML para mostrar la información por la pantalla LED. Los datos son enviados periódicamente a la BBDD ubicada fuera de la Raspberry.
def escribeXML(campo, valor, fecha):
tree = ET.parse(os.getcwd()+'/pantalla.xml')
root = tree.getroot()
for country in root.findall("./*[@Titulo='"+campo+"']"):
for mi in country.iter("Valor"):
mi.text = str(round(valor, 2))
for mi in country.iter("Fecha"):
mi.text = str(fecha)
tree.write(os.getcwd()+'/pantalla.xml')
Tenemos organizados el árbol XML en 7 categorías, una por cada sensor. El campo Acro viene a ser la abreviatura, Valor el último valor obtenido, Formato es la unidad de medida utilizada, Fecha cuando se obtuvo la medida y el campo Enable no lo uso, pero sería para ocultar la aparición en la pantalla.
<Sensores>
<Tipo Titulo="humedad">
<Acro>H</Acro>
<Valor>76.3</Valor>
<Formato>%</Formato>
<Fecha>2021-09-26 19:27:12</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="temperatura">
<Acro>T</Acro>
<Valor>25.1</Valor>
<Formato>ºC</Formato>
<Fecha>2021-09-26 19:27:12</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="UV">
<Acro>UV</Acro>
<Valor>0.18</Valor>
<Formato>mW...</Formato>
<Fecha>2021-09-26 19:27:02</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="luz">
<Acro>L</Acro>
<Valor>73.33</Valor>
<Formato>lm</Formato>
<Fecha>2021-09-26 19:27:07</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="Fan">
<Acro>CPU</Acro>
<Valor>45.46</Valor>
<Formato>ºC</Formato>
<Fecha>2021-09-26 19:27:32</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="PAtmosferica">
<Acro>P.</Acro>
<Valor>1014.84</Valor>
<Formato>hPa</Formato>
<Fecha>2021-09-26 19:27:12</Fecha>
<Enable>True</Enable>
</Tipo>
<Tipo Titulo="Lluvia">
<Acro>LL.</Acro>
<Valor>0</Valor>
<Formato>hPa</Formato>
<Fecha>2021-09-26 19:18:44</Fecha>
<Enable>True</Enable>
</Tipo>
</Sensores>
Nombre del fichero: obtenserial.py
Obtiene el número de serie de la RaspBerry, todos los registros son guardados en al base de datos con el número de serie, esto nos permitirá en un futuro ampliar la red con otras Raspberrys en otras ubicaciones.
def getserial():
# Extract serial from cpuinfo file
cpuserial = "0000000000000000"
try:
f = open('/proc/cpuinfo','r')
for line in f:
if line[0:6]=='Serial':
cpuserial = line[10:26]
f.close()
except:
cpuserial = "ERROR000000000"
return cpuserial
Nombre del fichero: fotoresistor.py
Librería utilizadas:
#Modulos Sistema
import smbus
import time
import writefile
import datetime
En este caso la dirección de I2C del hardawre es 0x23. Podemos obenter la información ejecutando el comando sudo i2cdetect -y 1, al final de este apartado explico como obtenerlo y que elemento es cada dirección.
# Define some constants from the datasheet
DEVICE = 0x23 # Default device I2C address
Realizamos una evaluación de las medidas cada 5 segundos y guardamos los valores si hay una variación de ± 5%.
def main(Luz_ant):
suma_luz = 0
suma_ant = Luz_ant
try:
lightLevel = readLight()
suma_luz = float(lightLevel)
if suma_luz > 0:
# Enviamos a la web cuando hay cambios del +-5%
if suma_luz > suma_ant+(suma_ant*5/100) or suma_luz < suma_ant - (suma_ant*5/100):
# Generamos la hora
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
suma_ant = suma_luz
print("LUZ")
print("---")
print(utc)
print("L " + str(suma_luz))
print("")
# Redondeamos a 2 decimales para que la BBDD guarde bien los datos
writefile.setfile("luz", round(suma_luz, 2))
else:
print("error Revisa el Sistema de Fotoresistor")
time.sleep(5)
except (KeyboardInterrupt, SystemExit):
raise
return(suma_ant)
En nuestro caso tenemos las siguiente direciones I2C:
aste@Serv-Jardin:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
En nuestro caso las direcciones correponden a:
Nombre del fichero: pulsador.py
Librería utilizadas:
#Modulos Sistema
import datetime
import subprocess
import time
import adafruit_ssd1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
#Modulos Propios
import muestra
La función del pulsador es mostrar por la pantalla Led una serie de información como puede ser la fecha, la temperatura la humedad... para ello lee la información de un fichero XML, donde vamos guardando los últimos valores obtenidos.
En teoría cuando pulsas el botón empieza a circular la electricidad. Hasta el momento no hemos encontrado el motivo que aunque no se pulse el botón hay algo de circulación eléctrica.
try:
while (True):
# Como existe ruido, hemos tenido de dejar de usar .value!=0): Asi ignoramos el ruido
if (AnalogIn(mcp, MCP.P4).value > 2000):
Esta parte del código va destinada para crear la salida de pantalla.
Con muestra.leeXML(), llamamos a la clase encargada de leer el fichero XML con la información.
# Clear display.
oled.fill(0)
oled.show()
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = oled.width
height = oled.height
image = Image.new('1', (width, height))
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0
# Load default font.
#font = ImageFont.load_default()
# Alternatively load a TTF font. Make sure the .ttf font file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
font = ImageFont.truetype('Minecraftia-Regular.ttf', 8)
datetime2 = datetime.datetime.now()
# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)
# Shell scripts for system monitoring from here : https://unix.stackexchange.com/questions/119126/ommand-to-display-memory-usage-disk-usage-and-cpu-load
cmd = "hostname -I"
IP = subprocess.check_output(cmd, shell=True)
IP = str(IP)
IP = IP[2:IP.find(' ')]
draw.text((x, top), str(datetime2.strftime(
"%d/%m/%Y %H:%M")), font=font, fill=255)
draw.text((x, top + 9), IP, font=font, fill=255)
draw.text((110, top), ("BAT"), font=font, fill=255)
draw.text((105, top+9), ("100%"), font=font, fill=255)
info = muestra.leeXML()
ix = 2
i = 0
for salida in info:
if i == 0:
draw.text((x, top + 9*ix), salida, font=font, fill=255)
i = 1
elif i == 1:
draw.text((x+45, top + 9*ix), "| " +
salida, font=font, fill=255)
i = 2
else:
draw.text((x+90, top + 9*ix), "| " +
salida, font=font, fill=255)
i = 0
ix = ix+1
# Display image.
oled.image(image)
oled.show()
time.sleep(10)
# Clear display.
oled.fill(0)
oled.show()
Nombre del fichero: UV.py
Librería utilizadas:
#Modulos Sistema
import datetime
import time
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
#Modulos Propios
import convert_ard_TO_ras
import writefile
Cabe destacar como parte del código importante que estamos usando el pin 22, equivale al GPIO22 (conector 15), para conectar el sensor a la Raspberry.
def calcula_UV(UV_ant):
i = 0
suma_UV = 0
suma_ant = UV_ant
suma_3v3 = 0
# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the cs (chip select) Orignalmente D5 (Gpio5, conector 29)
cs = digitalio.DigitalInOut(board.D22)
# create the mcp object
mcp = MCP.MCP3008(spi, cs)
try:
while i < 12:
# Canal 1
valor_UV = AnalogIn(mcp, MCP.P1).value
# Canal 2
valor_3v3 = AnalogIn(mcp, MCP.P2).value
Recuperamos los valores del sensore de UV, y como la fórmula usada está pensada para Arduino transformamos los valores, un poco más adelante explicamos con que clase lo realizamos. No se muestra ni se explica el algoritmo aplicado lo encontrarás en el fichero Python correspondienete.
# Homogeneizamos los valores del MPC3008 al ADC de arduino
valor_UV = float(convert_ard_TO_ras.Con_ras3v3_TO_ard(valor_UV))
valor_3v3 = float(convert_ard_TO_ras.Con_ras3v3_TO_ard(valor_3v3))
[...]
Se evalua los datos cada 1 minutos, con 12 tomas realizadas cada 5 segundos y subiermos los datos a la web cuando haya un cambio de +- 0,5. Guardaremos los datos con hora UTC, de esta manera evitamos discrepancias horarias de la toma de datos.
[...]
# Generamos la hora
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
# Enviamos a la web cuando hay cambios del +-0,5 del valor
# Ponemos 0 porque el valor por defecto es 0 y necesitamos una primera toma para que pueda evaluar.
if suma_ant==0 or suma_UV >= suma_ant+(0.5) or suma_UV <= suma_ant - (0.5):
suma_ant = suma_UV
print("UV")
print("------------------")
print(utc)
print("UV " + str(suma_UV))
print("------------------")
# Redondeamos a 2 decimales para que la BBDD guarde bien los datos
writefile.setfile("UV", round(suma_UV, 2))
time.sleep(5)
Nombre del fichero: convert_ard_TO_ras.py
En este fichero tiene unas clases para convertir los valores dados por el conversor Analógico-Digital MPC3008 a valores similares que daría un Arduino y viceversa. Las clases hace posible que usemos scripts para Arduino y una vez que los hayamos transformado usar la salida Analógica que nos de el MPC3008 con las fórmulas propuestas inicialmente por el Script del Arduino.
Podemos transformar los valores de la siguiente manera:
def Con_ras_TO_ard(valor):
#Homologamos un valor obtenido de MPC3008 a un valor de Arduino de 5v
#Usar este si trabajas con MPC3008 y 5v y el codigo de ejemplo es de arduino
resultado= (1023*valor)/65535
return (resultado)
def Con_ard_TO_Ras(valor):
#Homologamos un valor obtenido en un Arduino de 5v a un valor MPC3008
resultado=(65535*valor)/1023
return (resultado)
def Con_ras3v3_TO_ard(valor):
#Homologamos un valor obtenido de MPC3008 a un valor de Arduino 3.3v
#Usar este si trabajas con MPC3008 y 3.3v y el codigo de ejemplo es de arduino
valor=Con_ras_TO_ard(valor)
resultado= (valor*3.3)/5
return (resultado)
def Con_ard_TO_ras3v3(valor):
#Homologamos un valor obtenido en un Arduino 3.3v a un valor MPC3008
valor=Con_ard_TO_Ras(valor)
resultado=(5*valor)/3.3
return (resultado)
Nombre del fichero: updatorSFTP.py
Librería utilizadas:
#Modulos Sistema
import paramiko
import os
import datetime
#Modulos Propios
import writefile
La función de este fichero es preprar los ficheros para subirlos a la plataforma web.
def updator():
try:
# Cargamos las variables de uso
variablesuso()
global pathBase
# Me aseguro de guardar una variable del path principal
pathBase = os.getcwd()
# --Escaneamos ficheros en /csv
file_scan = Scanfile()
# Cambiamos el directorio de trabajo
if (os.getcwd().find('/csv') == -1):
old_parent = os.getcwd()
os.chdir(os.getcwd() + "/csv")
# --Leemos el array y subimos al FTP
for item in file_scan:
log = (upload(item))
writefile.setlog("ftp", log, pathBase)
print("Fichero enviado a Web")
print("-------------------------------")
print(log)
# Nos aseguramos que el directorio de trabajo sea desde el que estamos ejecutando la aplicacion
os.chdir(old_parent)
except (KeyboardInterrupt, SystemExit):
raise
En esta parte del fichero se encarga de buscar en un directorio dado todos los ficheros con extensión CSV.
def Scanfile():
fichero_CSV = []
for file in os.listdir("./csv"):
if file.endswith(".csv"):
fichero_CSV.append(file)
return (fichero_CSV)
Con esta parte del código gestionamos e imprimimos por pantalla los ficheros CSV que se van enviando a la plataforma Web.
def upload(file):
# Try me aseguro que si no hay conexion continue ejecutandose el FTP aunque el servier este caido
utc = datetime.datetime.utcnow().strftime('%Y%m%d%H%M%S-')
utc_log = datetime.datetime.utcnow().strftime('%Y/%m/%d %H:%M:%S -')
print("-*-*-*-*-*-*-*-*-*-*-*-*")
print(ftp_server)
print("-*-*-*-*-*-*-*-*-*-*-*-*")
try:
ssh_transport = paramiko.Transport(ftp_server, 22)
# Sin clave ssl hace falta password
ssh_transport.connect(username=ftp_user, password=ftp_pass)
# Con clave ssl no hace falta password
#pk = paramiko.RSAKey.from_private_key_file('/home/aste/.ssh/id_rsa')
#ssh_transport.connect(username=ftp_user, pkey=pk)
sftp_session = paramiko.SFTPClient.from_transport(ssh_transport)
# Renombramos el fichero
file_new = utc + file
os.rename(file, file_new)
ext = os.path.splitext(file_new)[1]
if ext in (".txt", ".htm", ".html", ".csv"):
# Sube los ficheros por SFTP
sftp_session.put(file_new, PathCSV+"/"+file_new)
salida = (utc_log + " Fichero %s UP OK" % file_new)
# Borramos el fichero subido por SFTP
os.remove(file_new)
erasefile = (utc_log + " Fichero %s DELETE" % file_new)
writefile.setlog("delete", erasefile, pathBase)
else:
salida = (utc_log + " Fichero %s no esta permitido UP KO" % file_new)
sftp_session.close()
ssh_transport.close()
# Except permite manejare el error
except:
# Si se pierde la conectividad mostrara este mensaje
salida = (utc_log + " Servidor " + ftp_server + " INACCESIBLE")
variablesuso()
# Finally permite ejecutar codigo,independientemente del resultado de los bloques try y except.
finally:
print("-------------------------------")
# Referescamos variables por si hay cambio de servidor
return salida
Definimos variables globales. La gracia de esta parte del fichero es que si necesitamos cambiar la dirección IP/URL del servidor FTP o sus credenciales, no es necesario parar la aplicación. Tan sólo con modificar los datos requeridos en el fichero variables3.dat sería suficiente para que empezara a subir.
def variablesuso():
# definos las varialbes Globales. Se hace asi por si se cambia de servidor no hay que parar la ejecucion de la APP solo modificar el fichero variable.dat
global ftp_server, ftp_user, ftp_pass, FileCSV, PathCSV, host
# Buscamos si el direcotrio de trabajo acaba en la carpeta CSV
buscando_CSV = os.getcwd().find('/csv')
# volvemos al espacio de trabajo inicial sin la carpeta csv
if (buscando_CSV != -1):
os.chdir(os.getcwd()[:buscando_CSV])
fileName = "variables3.dat"
fileObj = open(fileName)
# Declaramos el array del servidor
params = {}
for line in fileObj:
line = line.strip()
if not line.startswith("#"):
key_value = line.split("=")
if len(key_value) == 2:
params[key_value[0].strip()] = key_value[1].strip()
ftp_server = params["ftp_server"]
ftp_user = params["ftp_user"]
ftp_pass = params["ftp_pass"]
FileCSV = params["ftp_server"]
PathCSV = params["Serv_PathCSV"]
host = params["host"]
fileObj.close()
Nombre del fichero: variables3.dat
En este fichero almacenaremos la IP o URL del servidor FTP (ftp_server), el Usuario (ftp_user) y la Contraseña (ftp_pass). Como también la ruta de trabajo (Serv_PathCSV). FileCSV y host no se están implementando para ningún desarrollo.
Un dato importante a saber, NO es necesario parar la aplicación de Python para poder cambiar algún parámetro del Servidor FTP, modificándolo en el fichero variables3.dat ya se efectua el cambio en caliente.
#David Marchena
#Valores centralizados
ftp_server = 192.168.1.97
ftp_user = miusuario
ftp_pass = micontraseña
Serv_PathCSV = /var/www/catalana.ga/csv
FileCSV = "./csv"
host = http://192.168.1.97/updator.php
Nombre del fichero: presionATM.py
Librería utilizadas:
#Modulos Sistema
import smbus
import datetime
import time
from ctypes import c_short
from ctypes import c_byte
from ctypes import c_ubyte
#Modulos Propios
import writefile
Indicar que en el dispositivo utilizado puede medir Humedad y Temperatura, pudiendo ser alternativa al DHT22. En nuestro caso no lo usamos porque no devuelve datos de la humedad. Sólo guardamos datos si varía la presión Atmosférica. Si la presión Atmosférica no varia no subimos datos a la base de datos. De esta manera optimizamos recursos. Como siempre usamos la sentencia writefile.setfile(...) para gestionar la subida de datos. Si por el motivo que fuera no devolviera un dato válido en el prompt de la Raspberry aparecía un mensaje de error.
def main(Pressure_ant):
pressures_ant = Pressure_ant
temperature, pressure, humidity = readBME280All()
try:
if pressure != 0:
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
if pressure > (pressures_ant+1) or pressure < (pressures_ant - 1):
pressures_ant = pressure
print("Presion Atomsoferica")
print("--------------------")
print(utc)
print("hPa " + str(pressure))
print("")
writefile.setfile("PAtmosferica", round(pressure, 2))
pressure = 0
else:
print("error Revisa el Sistema de Presion Atmosferica")
except (KeyboardInterrupt, SystemExit):
raise
return pressures_ant
Nombre del fichero: voltimetro.py
Librería utilizadas:
#Modulos Sistema
import datetime
import time
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
# #Modulos Propios
import writefile
import convert_ard_TO_ras
Esta parte de la aplicación está pensado para integrarlo con placas solares y poder controlar a distancia la carga de la baterías. Esta parte aún está en desarrollo. Tan pronto como tenga avances los actualizaré.
def calcula_bateria():
i = 0
suma_bateria = 0
suma_ant = 0
# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the cs (chip select) Orignalmente D5 (Gpio5, conector 29)
cs = digitalio.DigitalInOut(board.D22)
# create the mcp object
mcp = MCP.MCP3008(spi, cs)
try:
while True:
Vin=AnalogIn(mcp, MCP.P5).voltage
#usamos una bateria de 12v y el ADC solo le voltajes de hasta 3.3v
bateria=(12*Vin)/3.3
# Evaluamos la bateria cada 12 periodos de 5 segundos por tanto 1 minuto
suma_bateria = suma_bateria + bateria
i = i + 1
if suma_bateria!=0:
if i == 12:
#Hacemos una media en un minuto del voltaje en la bateria
suma_bateria = suma_bateria / 12
# Generamos la hora
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
i = 0
# Enviamos a la web cuando hay cambios del +-1%
if suma_bateria > suma_ant+(suma_ant*1/100) or suma_bateria< suma_ant -(suma_ant*1/100):
suma_ant=0
suma_ant = suma_bateria
print ("Bateria")
print ("-------")
print (utc)
print ("V "+ str(suma_bateria))
print ("")
#Redondeamos a 2 decimales para que la BBDD guarde bien los datos
writefile.setfile("Bateria", round (suma_bateria,2))
#ponemos el contador a 0
suma_bateria = 0
else:
print("error Revisa el Sistema de Baterias")
time.sleep(5)
except (KeyboardInterrupt, SystemExit):
raise
Nombre del fichero: writefile.py
Librería utilizadas:
#Modulos Sistema
import datetime
import os
#Modulos Propios
import obtenserial
import muestra
Esta es la parte de la aplicación que se encarga de genrar de crear los ficheros CSV y manteneder actualizado el fichero XML. Como siempre usaremos para guardar los datos la hora UTC.
def setfile(file, value):
# Obtiene elnumero de serie de la raspberry
piserial = obtenserial.getserial()
utc = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
buscando_CSV = os.getcwd().find('/csv')
# volvemos al espacio de trabajo inicial sin la carpeta csv
if (buscando_CSV != -1):
caminosanto = os.getcwd() + "/"
else:
caminosanto = os.getcwd() + "/csv/"
f = open(caminosanto + file + ".csv", "a")
f.write(utc + "," + str(value) + "," + piserial + "\n")
f.close()
#actualizamos el fichero XML
muestra.escribeXML(file,round (value,2),utc)
def setlog(file, value, ruta_primaria):
f = open(ruta_primaria + "/log/" + file + ".log", "a")
f.write(str(value) + "\n")
f.close()